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/heap.h"
32 #include "wine/list.h"
34 #include "mf_private.h"
38 DEFINE_GUID(_MF_TOPONODE_IMFActivate
, 0x33706f4a, 0x309a, 0x49be, 0xa8, 0xdd, 0xe7, 0xc0, 0x87, 0x5e, 0xb6, 0x79);
40 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
44 SESSION_CMD_CLEAR_TOPOLOGIES
,
46 SESSION_CMD_SET_TOPOLOGY
,
50 /* Internally used commands. */
52 SESSION_CMD_QM_NOTIFY_TOPOLOGY
,
58 IUnknown IUnknown_iface
;
60 enum session_command command
;
66 IMFTopology
*topology
;
71 PROPVARIANT start_position
;
75 IMFTopology
*topology
;
85 struct queued_topology
88 IMFTopology
*topology
;
94 SESSION_STATE_STOPPED
= 0,
95 SESSION_STATE_STARTING_SOURCES
,
96 SESSION_STATE_PREROLLING_SINKS
,
97 SESSION_STATE_STARTING_SINKS
,
98 SESSION_STATE_STARTED
,
99 SESSION_STATE_PAUSING_SINKS
,
100 SESSION_STATE_PAUSING_SOURCES
,
101 SESSION_STATE_PAUSED
,
102 SESSION_STATE_STOPPING_SINKS
,
103 SESSION_STATE_STOPPING_SOURCES
,
104 SESSION_STATE_FINALIZING_SINKS
,
105 SESSION_STATE_CLOSED
,
106 SESSION_STATE_SHUT_DOWN
,
111 OBJ_STATE_STOPPED
= 0,
118 enum media_source_flags
120 SOURCE_FLAG_END_OF_PRESENTATION
= 0x1,
126 IMFMediaSource
*source
;
127 IMFPresentationDescriptor
*pd
;
128 enum object_state state
;
136 IMFMediaSinkPreroll
*preroll
;
137 IMFMediaEventGenerator
*event_generator
;
147 struct transform_stream
150 unsigned int requests
;
151 unsigned int min_buffer_size
;
156 TOPO_NODE_END_OF_STREAM
= 0x1,
162 struct media_session
*session
;
163 MF_TOPOLOGY_TYPE type
;
165 IMFTopologyNode
*node
;
166 enum object_state state
;
170 IMFMediaStream
*source_stream
;
171 IMFStreamSink
*sink_stream
;
172 IMFTransform
*transform
;
180 IMFMediaSource
*source
;
181 unsigned int stream_id
;
185 unsigned int requests
;
186 IMFVideoSampleAllocatorNotify notify_cb
;
187 IMFVideoSampleAllocator
*allocator
;
188 IMFVideoSampleAllocatorCallback
*allocator_cb
;
192 struct transform_stream
*inputs
;
193 unsigned int *input_map
;
194 unsigned int input_count
;
196 struct transform_stream
*outputs
;
197 unsigned int *output_map
;
198 unsigned int output_count
;
203 enum presentation_flags
205 SESSION_FLAG_SOURCES_SUBSCRIBED
= 0x1,
206 SESSION_FLAG_PRESENTATION_CLOCK_SET
= 0x2,
207 SESSION_FLAG_FINALIZE_SINKS
= 0x4,
208 SESSION_FLAG_NEEDS_PREROLL
= 0x8,
209 SESSION_FLAG_END_OF_PRESENTATION
= 0x10,
214 IMFMediaSession IMFMediaSession_iface
;
215 IMFGetService IMFGetService_iface
;
216 IMFRateSupport IMFRateSupport_iface
;
217 IMFRateControl IMFRateControl_iface
;
218 IMFTopologyNodeAttributeEditor IMFTopologyNodeAttributeEditor_iface
;
219 IMFAsyncCallback commands_callback
;
220 IMFAsyncCallback events_callback
;
221 IMFAsyncCallback sink_finalizer_callback
;
223 IMFMediaEventQueue
*event_queue
;
224 IMFPresentationClock
*clock
;
225 IMFPresentationTimeSource
*system_time_source
;
226 IMFRateControl
*clock_rate_control
;
227 IMFTopoLoader
*topo_loader
;
228 IMFQualityManager
*quality_manager
;
231 IMFTopology
*current_topology
;
232 MF_TOPOSTATUS topo_status
;
233 MFTIME clock_stop_time
;
239 /* Latest Start() arguments. */
241 PROPVARIANT start_position
;
243 struct list topologies
;
244 struct list commands
;
245 enum session_state state
;
250 enum quality_manager_state
252 QUALITY_MANAGER_READY
= 0,
253 QUALITY_MANAGER_SHUT_DOWN
,
256 struct quality_manager
258 IMFQualityManager IMFQualityManager_iface
;
259 IMFClockStateSink IMFClockStateSink_iface
;
262 IMFTopology
*topology
;
263 IMFPresentationClock
*clock
;
268 static inline struct media_session
*impl_from_IMFMediaSession(IMFMediaSession
*iface
)
270 return CONTAINING_RECORD(iface
, struct media_session
, IMFMediaSession_iface
);
273 static struct media_session
*impl_from_commands_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
275 return CONTAINING_RECORD(iface
, struct media_session
, commands_callback
);
278 static struct media_session
*impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
280 return CONTAINING_RECORD(iface
, struct media_session
, events_callback
);
283 static struct media_session
*impl_from_sink_finalizer_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
285 return CONTAINING_RECORD(iface
, struct media_session
, sink_finalizer_callback
);
288 static struct media_session
*impl_from_IMFGetService(IMFGetService
*iface
)
290 return CONTAINING_RECORD(iface
, struct media_session
, IMFGetService_iface
);
293 static struct media_session
*impl_session_from_IMFRateSupport(IMFRateSupport
*iface
)
295 return CONTAINING_RECORD(iface
, struct media_session
, IMFRateSupport_iface
);
298 static struct media_session
*impl_session_from_IMFRateControl(IMFRateControl
*iface
)
300 return CONTAINING_RECORD(iface
, struct media_session
, IMFRateControl_iface
);
303 static struct media_session
*impl_session_from_IMFTopologyNodeAttributeEditor(IMFTopologyNodeAttributeEditor
*iface
)
305 return CONTAINING_RECORD(iface
, struct media_session
, IMFTopologyNodeAttributeEditor_iface
);
308 static struct session_op
*impl_op_from_IUnknown(IUnknown
*iface
)
310 return CONTAINING_RECORD(iface
, struct session_op
, IUnknown_iface
);
313 static struct quality_manager
*impl_from_IMFQualityManager(IMFQualityManager
*iface
)
315 return CONTAINING_RECORD(iface
, struct quality_manager
, IMFQualityManager_iface
);
318 static struct quality_manager
*impl_from_qm_IMFClockStateSink(IMFClockStateSink
*iface
)
320 return CONTAINING_RECORD(iface
, struct quality_manager
, IMFClockStateSink_iface
);
323 static struct topo_node
*impl_node_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify
*iface
)
325 return CONTAINING_RECORD(iface
, struct topo_node
, u
.sink
.notify_cb
);
328 /* IMFLocalMFTRegistration */
329 static HRESULT WINAPI
local_mft_registration_QueryInterface(IMFLocalMFTRegistration
*iface
, REFIID riid
, void **obj
)
331 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
333 if (IsEqualIID(riid
, &IID_IMFLocalMFTRegistration
) ||
334 IsEqualIID(riid
, &IID_IUnknown
))
337 IMFLocalMFTRegistration_AddRef(iface
);
341 WARN("Unexpected %s.\n", debugstr_guid(riid
));
343 return E_NOINTERFACE
;
346 static ULONG WINAPI
local_mft_registration_AddRef(IMFLocalMFTRegistration
*iface
)
351 static ULONG WINAPI
local_mft_registration_Release(IMFLocalMFTRegistration
*iface
)
356 static HRESULT WINAPI
local_mft_registration_RegisterMFTs(IMFLocalMFTRegistration
*iface
, MFT_REGISTRATION_INFO
*info
,
362 TRACE("%p, %p, %u.\n", iface
, info
, count
);
364 for (i
= 0; i
< count
; ++i
)
366 if (FAILED(hr
= MFTRegisterLocalByCLSID(&info
[i
].clsid
, &info
[i
].guidCategory
, info
[i
].pszName
,
367 info
[i
].uiFlags
, info
[i
].cInTypes
, info
[i
].pInTypes
, info
[i
].cOutTypes
, info
[i
].pOutTypes
)))
376 static const IMFLocalMFTRegistrationVtbl local_mft_registration_vtbl
=
378 local_mft_registration_QueryInterface
,
379 local_mft_registration_AddRef
,
380 local_mft_registration_Release
,
381 local_mft_registration_RegisterMFTs
,
384 static IMFLocalMFTRegistration local_mft_registration
= { &local_mft_registration_vtbl
};
386 static HRESULT WINAPI
session_op_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
388 if (IsEqualIID(riid
, &IID_IUnknown
))
391 IUnknown_AddRef(iface
);
396 return E_NOINTERFACE
;
399 static ULONG WINAPI
session_op_AddRef(IUnknown
*iface
)
401 struct session_op
*op
= impl_op_from_IUnknown(iface
);
402 ULONG refcount
= InterlockedIncrement(&op
->refcount
);
404 TRACE("%p, refcount %u.\n", iface
, refcount
);
409 static ULONG WINAPI
session_op_Release(IUnknown
*iface
)
411 struct session_op
*op
= impl_op_from_IUnknown(iface
);
412 ULONG refcount
= InterlockedDecrement(&op
->refcount
);
414 TRACE("%p, refcount %u.\n", iface
, refcount
);
420 case SESSION_CMD_SET_TOPOLOGY
:
421 if (op
->u
.set_topology
.topology
)
422 IMFTopology_Release(op
->u
.set_topology
.topology
);
424 case SESSION_CMD_START
:
425 PropVariantClear(&op
->u
.start
.start_position
);
427 case SESSION_CMD_QM_NOTIFY_TOPOLOGY
:
428 if (op
->u
.notify_topology
.topology
)
429 IMFTopology_Release(op
->u
.notify_topology
.topology
);
440 static const IUnknownVtbl session_op_vtbl
=
442 session_op_QueryInterface
,
447 static HRESULT
create_session_op(enum session_command command
, struct session_op
**ret
)
449 struct session_op
*op
;
451 if (!(op
= heap_alloc_zero(sizeof(*op
))))
452 return E_OUTOFMEMORY
;
454 op
->IUnknown_iface
.lpVtbl
= &session_op_vtbl
;
456 op
->command
= command
;
463 static HRESULT
session_is_shut_down(struct media_session
*session
)
465 return session
->state
== SESSION_STATE_SHUT_DOWN
? MF_E_SHUTDOWN
: S_OK
;
468 static void session_push_back_command(struct media_session
*session
, enum session_command command
)
470 struct session_op
*op
;
472 if (SUCCEEDED(create_session_op(command
, &op
)))
473 list_add_head(&session
->commands
, &op
->entry
);
476 static HRESULT
session_submit_command(struct media_session
*session
, struct session_op
*op
)
480 EnterCriticalSection(&session
->cs
);
481 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
483 if (list_empty(&session
->commands
))
484 hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &session
->commands_callback
, &op
->IUnknown_iface
);
485 list_add_tail(&session
->commands
, &op
->entry
);
486 IUnknown_AddRef(&op
->IUnknown_iface
);
488 LeaveCriticalSection(&session
->cs
);
493 static HRESULT
session_submit_simple_command(struct media_session
*session
, enum session_command command
)
495 struct session_op
*op
;
498 if (FAILED(hr
= create_session_op(command
, &op
)))
501 hr
= session_submit_command(session
, op
);
502 IUnknown_Release(&op
->IUnknown_iface
);
506 static void session_clear_topologies(struct media_session
*session
)
508 struct queued_topology
*ptr
, *next
;
510 LIST_FOR_EACH_ENTRY_SAFE(ptr
, next
, &session
->topologies
, struct queued_topology
, entry
)
512 list_remove(&ptr
->entry
);
513 IMFTopology_Release(ptr
->topology
);
518 static void session_set_topo_status(struct media_session
*session
, HRESULT status
,
519 MF_TOPOSTATUS topo_status
)
521 IMFMediaEvent
*event
;
524 if (topo_status
== MF_TOPOSTATUS_INVALID
)
527 if (list_empty(&session
->topologies
))
529 FIXME("Unexpectedly empty topology queue.\n");
533 if (topo_status
> session
->presentation
.topo_status
)
535 struct queued_topology
*topology
= LIST_ENTRY(list_head(&session
->topologies
), struct queued_topology
, entry
);
537 param
.vt
= VT_UNKNOWN
;
538 param
.punkVal
= (IUnknown
*)topology
->topology
;
540 if (FAILED(MFCreateMediaEvent(MESessionTopologyStatus
, &GUID_NULL
, status
, ¶m
, &event
)))
543 session
->presentation
.topo_status
= topo_status
;
545 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_TOPOLOGY_STATUS
, topo_status
);
546 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
547 IMFMediaEvent_Release(event
);
551 static HRESULT
session_bind_output_nodes(IMFTopology
*topology
)
553 MF_TOPOLOGY_TYPE node_type
;
554 IMFStreamSink
*stream_sink
;
555 IMFMediaSink
*media_sink
;
556 WORD node_count
= 0, i
;
557 IMFTopologyNode
*node
;
558 IMFActivate
*activate
;
563 hr
= IMFTopology_GetNodeCount(topology
, &node_count
);
565 for (i
= 0; i
< node_count
; ++i
)
567 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
570 if (FAILED(hr
= IMFTopologyNode_GetNodeType(node
, &node_type
)) || node_type
!= MF_TOPOLOGY_OUTPUT_NODE
)
572 IMFTopologyNode_Release(node
);
576 if (SUCCEEDED(hr
= IMFTopologyNode_GetObject(node
, &object
)))
579 if (FAILED(IUnknown_QueryInterface(object
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
581 if (SUCCEEDED(hr
= IUnknown_QueryInterface(object
, &IID_IMFActivate
, (void **)&activate
)))
583 if (SUCCEEDED(hr
= IMFActivate_ActivateObject(activate
, &IID_IMFMediaSink
, (void **)&media_sink
)))
585 if (FAILED(IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_STREAMID
, &stream_id
)))
589 if (FAILED(IMFMediaSink_GetStreamSinkById(media_sink
, stream_id
, &stream_sink
)))
590 hr
= IMFMediaSink_AddStreamSink(media_sink
, stream_id
, NULL
, &stream_sink
);
593 hr
= IMFTopologyNode_SetObject(node
, (IUnknown
*)stream_sink
);
595 IMFMediaSink_Release(media_sink
);
599 IMFTopologyNode_SetUnknown(node
, &_MF_TOPONODE_IMFActivate
, (IUnknown
*)activate
);
601 IMFActivate_Release(activate
);
606 IMFStreamSink_Release(stream_sink
);
607 IUnknown_Release(object
);
610 IMFTopologyNode_Release(node
);
616 static void session_set_caps(struct media_session
*session
, DWORD caps
)
618 DWORD delta
= session
->caps
^ caps
;
619 IMFMediaEvent
*event
;
621 /* Delta is documented to reflect rate value changes as well, but it's not clear what to compare
622 them to, since session always queries for current object rates. */
626 session
->caps
= caps
;
628 if (FAILED(MFCreateMediaEvent(MESessionCapabilitiesChanged
, &GUID_NULL
, S_OK
, NULL
, &event
)))
631 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_SESSIONCAPS
, caps
);
632 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_SESSIONCAPS_DELTA
, delta
);
634 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
635 IMFMediaEvent_Release(event
);
638 static void transform_release_sample(struct sample
*sample
)
640 list_remove(&sample
->entry
);
642 IMFSample_Release(sample
->sample
);
646 static void transform_stream_drop_samples(struct transform_stream
*stream
)
648 struct sample
*sample
, *sample2
;
650 LIST_FOR_EACH_ENTRY_SAFE(sample
, sample2
, &stream
->samples
, struct sample
, entry
)
651 transform_release_sample(sample
);
654 static void release_topo_node(struct topo_node
*node
)
660 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
661 if (node
->u
.source
.source
)
662 IMFMediaSource_Release(node
->u
.source
.source
);
664 case MF_TOPOLOGY_TRANSFORM_NODE
:
665 for (i
= 0; i
< node
->u
.transform
.input_count
; ++i
)
666 transform_stream_drop_samples(&node
->u
.transform
.inputs
[i
]);
667 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
668 transform_stream_drop_samples(&node
->u
.transform
.outputs
[i
]);
669 heap_free(node
->u
.transform
.inputs
);
670 heap_free(node
->u
.transform
.outputs
);
671 heap_free(node
->u
.transform
.input_map
);
672 heap_free(node
->u
.transform
.output_map
);
674 case MF_TOPOLOGY_OUTPUT_NODE
:
675 if (node
->u
.sink
.allocator
)
676 IMFVideoSampleAllocator_Release(node
->u
.sink
.allocator
);
677 if (node
->u
.sink
.allocator_cb
)
679 IMFVideoSampleAllocatorCallback_SetCallback(node
->u
.sink
.allocator_cb
, NULL
);
680 IMFVideoSampleAllocatorCallback_Release(node
->u
.sink
.allocator_cb
);
687 if (node
->object
.object
)
688 IUnknown_Release(node
->object
.object
);
690 IMFTopologyNode_Release(node
->node
);
694 static void session_shutdown_current_topology(struct media_session
*session
)
696 unsigned int shutdown
, force_shutdown
;
697 MF_TOPOLOGY_TYPE node_type
;
698 IMFStreamSink
*stream_sink
;
699 IMFTopology
*topology
;
700 IMFTopologyNode
*node
;
701 IMFActivate
*activate
;
706 topology
= session
->presentation
.current_topology
;
707 force_shutdown
= session
->state
== SESSION_STATE_SHUT_DOWN
;
709 /* FIXME: should handle async MFTs, but these are not supported by the rest of the pipeline currently. */
711 while (SUCCEEDED(IMFTopology_GetNode(topology
, idx
++, &node
)))
713 if (SUCCEEDED(IMFTopologyNode_GetNodeType(node
, &node_type
)) &&
714 node_type
== MF_TOPOLOGY_OUTPUT_NODE
)
717 IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE
, &shutdown
);
719 if (force_shutdown
|| shutdown
)
721 if (SUCCEEDED(IMFTopologyNode_GetUnknown(node
, &_MF_TOPONODE_IMFActivate
, &IID_IMFActivate
,
722 (void **)&activate
)))
724 if (FAILED(hr
= IMFActivate_ShutdownObject(activate
)))
725 WARN("Failed to shut down activation object for the sink, hr %#x.\n", hr
);
726 IMFActivate_Release(activate
);
728 else if (SUCCEEDED(topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
730 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink
, &sink
)))
732 IMFMediaSink_Shutdown(sink
);
733 IMFMediaSink_Release(sink
);
736 IMFStreamSink_Release(stream_sink
);
741 IMFTopologyNode_Release(node
);
745 static void session_clear_command_list(struct media_session
*session
)
747 struct session_op
*op
, *op2
;
749 LIST_FOR_EACH_ENTRY_SAFE(op
, op2
, &session
->commands
, struct session_op
, entry
)
751 list_remove(&op
->entry
);
752 IUnknown_Release(&op
->IUnknown_iface
);
756 static void session_clear_presentation(struct media_session
*session
)
758 struct media_source
*source
, *source2
;
759 struct media_sink
*sink
, *sink2
;
760 struct topo_node
*node
, *node2
;
762 session_shutdown_current_topology(session
);
764 IMFTopology_Clear(session
->presentation
.current_topology
);
765 session
->presentation
.topo_status
= MF_TOPOSTATUS_INVALID
;
767 LIST_FOR_EACH_ENTRY_SAFE(source
, source2
, &session
->presentation
.sources
, struct media_source
, entry
)
769 list_remove(&source
->entry
);
771 IMFMediaSource_Release(source
->source
);
773 IMFPresentationDescriptor_Release(source
->pd
);
777 LIST_FOR_EACH_ENTRY_SAFE(node
, node2
, &session
->presentation
.nodes
, struct topo_node
, entry
)
779 list_remove(&node
->entry
);
780 release_topo_node(node
);
783 LIST_FOR_EACH_ENTRY_SAFE(sink
, sink2
, &session
->presentation
.sinks
, struct media_sink
, entry
)
785 list_remove(&sink
->entry
);
788 IMFMediaSink_Release(sink
->sink
);
790 IMFMediaSinkPreroll_Release(sink
->preroll
);
791 if (sink
->event_generator
)
792 IMFMediaEventGenerator_Release(sink
->event_generator
);
797 static struct topo_node
*session_get_node_by_id(const struct media_session
*session
, TOPOID id
)
799 struct topo_node
*node
;
801 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
803 if (node
->node_id
== id
)
810 static void session_start(struct media_session
*session
, const GUID
*time_format
, const PROPVARIANT
*start_position
)
812 struct media_source
*source
;
815 switch (session
->state
)
817 case SESSION_STATE_STOPPED
:
818 case SESSION_STATE_PAUSED
:
820 session
->presentation
.time_format
= *time_format
;
821 session
->presentation
.start_position
.vt
= VT_EMPTY
;
822 PropVariantCopy(&session
->presentation
.start_position
, start_position
);
824 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
826 if (!(session
->presentation
.flags
& SESSION_FLAG_SOURCES_SUBSCRIBED
))
828 if (FAILED(hr
= IMFMediaSource_BeginGetEvent(source
->source
, &session
->events_callback
,
829 (IUnknown
*)source
->source
)))
831 WARN("Failed to subscribe to source events, hr %#x.\n", hr
);
835 if (FAILED(hr
= IMFMediaSource_Start(source
->source
, source
->pd
, &GUID_NULL
, start_position
)))
836 WARN("Failed to start media source %p, hr %#x.\n", source
->source
, hr
);
839 session
->presentation
.flags
|= SESSION_FLAG_SOURCES_SUBSCRIBED
;
840 session
->state
= SESSION_STATE_STARTING_SOURCES
;
842 case SESSION_STATE_STARTED
:
843 FIXME("Seeking is not implemented.\n");
845 case SESSION_STATE_CLOSED
:
846 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionStarted
, &GUID_NULL
,
847 MF_E_INVALIDREQUEST
, NULL
);
854 static void session_command_complete(struct media_session
*session
)
856 struct session_op
*op
;
859 /* Pop current command, submit next. */
860 if ((e
= list_head(&session
->commands
)))
862 op
= LIST_ENTRY(e
, struct session_op
, entry
);
863 list_remove(&op
->entry
);
864 IUnknown_Release(&op
->IUnknown_iface
);
867 if ((e
= list_head(&session
->commands
)))
869 op
= LIST_ENTRY(e
, struct session_op
, entry
);
870 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &session
->commands_callback
, &op
->IUnknown_iface
);
874 static void session_set_started(struct media_session
*session
)
876 struct media_source
*source
;
877 unsigned int caps
, flags
;
878 IMFMediaEvent
*event
;
880 session
->state
= SESSION_STATE_STARTED
;
882 caps
= session
->caps
| MFSESSIONCAP_PAUSE
;
884 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
886 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source
->source
, &flags
)))
888 if (!(flags
& MFMEDIASOURCE_CAN_PAUSE
))
890 caps
&= ~MFSESSIONCAP_PAUSE
;
896 session_set_caps(session
, caps
);
898 if (SUCCEEDED(MFCreateMediaEvent(MESessionStarted
, &GUID_NULL
, S_OK
, NULL
, &event
)))
900 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_PRESENTATION_TIME_OFFSET
, 0);
901 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
902 IMFMediaEvent_Release(event
);
904 session_command_complete(session
);
907 static void session_set_paused(struct media_session
*session
, HRESULT status
)
909 session
->state
= SESSION_STATE_PAUSED
;
910 if (SUCCEEDED(status
))
911 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
912 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionPaused
, &GUID_NULL
, status
, NULL
);
913 session_command_complete(session
);
916 static void session_set_closed(struct media_session
*session
, HRESULT status
)
918 session
->state
= SESSION_STATE_CLOSED
;
919 if (SUCCEEDED(status
))
920 session_set_caps(session
, session
->caps
& ~(MFSESSIONCAP_START
| MFSESSIONCAP_SEEK
));
921 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionClosed
, &GUID_NULL
, status
, NULL
);
922 session_command_complete(session
);
925 static void session_pause(struct media_session
*session
)
929 switch (session
->state
)
931 case SESSION_STATE_STARTED
:
933 /* Transition in two steps - pause the clock, wait for sinks, then pause sources. */
934 if (SUCCEEDED(hr
= IMFPresentationClock_Pause(session
->clock
)))
935 session
->state
= SESSION_STATE_PAUSING_SINKS
;
939 hr
= MF_E_INVALIDREQUEST
;
943 session_set_paused(session
, hr
);
946 static void session_set_stopped(struct media_session
*session
, HRESULT status
)
948 MediaEventType event_type
;
949 IMFMediaEvent
*event
;
951 session
->state
= SESSION_STATE_STOPPED
;
952 event_type
= session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
? MESessionEnded
: MESessionStopped
;
954 if (SUCCEEDED(MFCreateMediaEvent(event_type
, &GUID_NULL
, status
, NULL
, &event
)))
956 IMFMediaEvent_SetUINT64(event
, &MF_SESSION_APPROX_EVENT_OCCURRENCE_TIME
, session
->presentation
.clock_stop_time
);
957 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
958 IMFMediaEvent_Release(event
);
960 session_command_complete(session
);
963 static void session_stop(struct media_session
*session
)
965 HRESULT hr
= MF_E_INVALIDREQUEST
;
967 switch (session
->state
)
969 case SESSION_STATE_STARTED
:
970 case SESSION_STATE_PAUSED
:
972 /* Transition in two steps - stop the clock, wait for sinks, then stop sources. */
973 IMFPresentationClock_GetTime(session
->clock
, &session
->presentation
.clock_stop_time
);
974 if (SUCCEEDED(hr
= IMFPresentationClock_Stop(session
->clock
)))
975 session
->state
= SESSION_STATE_STOPPING_SINKS
;
977 session_set_stopped(session
, hr
);
980 case SESSION_STATE_STOPPED
:
984 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionStopped
, &GUID_NULL
, hr
, NULL
);
985 session_command_complete(session
);
990 static HRESULT
session_finalize_sinks(struct media_session
*session
)
992 IMFFinalizableMediaSink
*fin_sink
;
993 BOOL sinks_finalized
= TRUE
;
994 struct media_sink
*sink
;
997 session
->presentation
.flags
&= ~SESSION_FLAG_FINALIZE_SINKS
;
998 session
->state
= SESSION_STATE_FINALIZING_SINKS
;
1000 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1002 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFFinalizableMediaSink
, (void **)&fin_sink
)))
1004 hr
= IMFFinalizableMediaSink_BeginFinalize(fin_sink
, &session
->sink_finalizer_callback
,
1005 (IUnknown
*)fin_sink
);
1006 IMFFinalizableMediaSink_Release(fin_sink
);
1009 sinks_finalized
= FALSE
;
1012 sink
->finalized
= TRUE
;
1015 if (sinks_finalized
)
1016 session_set_closed(session
, hr
);
1021 static void session_close(struct media_session
*session
)
1025 switch (session
->state
)
1027 case SESSION_STATE_STOPPED
:
1028 hr
= session_finalize_sinks(session
);
1030 case SESSION_STATE_STARTED
:
1031 case SESSION_STATE_PAUSED
:
1032 session
->presentation
.flags
|= SESSION_FLAG_FINALIZE_SINKS
;
1033 if (SUCCEEDED(hr
= IMFPresentationClock_Stop(session
->clock
)))
1034 session
->state
= SESSION_STATE_STOPPING_SINKS
;
1037 hr
= MF_E_INVALIDREQUEST
;
1042 session_set_closed(session
, hr
);
1045 static struct media_source
*session_get_media_source(struct media_session
*session
, IMFMediaSource
*source
)
1047 struct media_source
*cur
;
1049 LIST_FOR_EACH_ENTRY(cur
, &session
->presentation
.sources
, struct media_source
, entry
)
1051 if (source
== cur
->source
)
1058 static void session_release_media_source(struct media_source
*source
)
1060 IMFMediaSource_Release(source
->source
);
1062 IMFPresentationDescriptor_Release(source
->pd
);
1066 static HRESULT
session_add_media_source(struct media_session
*session
, IMFTopologyNode
*node
, IMFMediaSource
*source
)
1068 struct media_source
*media_source
;
1071 if (session_get_media_source(session
, source
))
1074 if (!(media_source
= heap_alloc_zero(sizeof(*media_source
))))
1075 return E_OUTOFMEMORY
;
1077 media_source
->source
= source
;
1078 IMFMediaSource_AddRef(media_source
->source
);
1080 hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_PRESENTATION_DESCRIPTOR
, &IID_IMFPresentationDescriptor
,
1081 (void **)&media_source
->pd
);
1084 list_add_tail(&session
->presentation
.sources
, &media_source
->entry
);
1086 session_release_media_source(media_source
);
1091 static void session_raise_topology_set(struct media_session
*session
, IMFTopology
*topology
, HRESULT status
)
1095 param
.vt
= topology
? VT_UNKNOWN
: VT_EMPTY
;
1096 param
.punkVal
= (IUnknown
*)topology
;
1098 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionTopologySet
, &GUID_NULL
, status
, ¶m
);
1101 static DWORD
session_get_object_rate_caps(IUnknown
*object
)
1103 IMFRateSupport
*rate_support
;
1107 if (SUCCEEDED(MFGetService(object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
, (void **)&rate_support
)))
1110 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support
, MFRATE_FORWARD
, TRUE
, &rate
)) && rate
!= 0.0f
)
1111 caps
|= MFSESSIONCAP_RATE_FORWARD
;
1114 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support
, MFRATE_REVERSE
, TRUE
, &rate
)) && rate
!= 0.0f
)
1115 caps
|= MFSESSIONCAP_RATE_REVERSE
;
1117 IMFRateSupport_Release(rate_support
);
1123 static HRESULT
session_add_media_sink(struct media_session
*session
, IMFTopologyNode
*node
, IMFMediaSink
*sink
)
1125 struct media_sink
*media_sink
;
1126 unsigned int disable_preroll
= 0;
1129 LIST_FOR_EACH_ENTRY(media_sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1131 if (sink
== media_sink
->sink
)
1135 if (!(media_sink
= heap_alloc_zero(sizeof(*media_sink
))))
1136 return E_OUTOFMEMORY
;
1138 media_sink
->sink
= sink
;
1139 IMFMediaSink_AddRef(media_sink
->sink
);
1141 IMFMediaSink_QueryInterface(media_sink
->sink
, &IID_IMFMediaEventGenerator
, (void **)&media_sink
->event_generator
);
1143 IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_DISABLE_PREROLL
, &disable_preroll
);
1144 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink
, &flags
)) && flags
& MEDIASINK_CAN_PREROLL
&& !disable_preroll
)
1146 if (SUCCEEDED(IMFMediaSink_QueryInterface(media_sink
->sink
, &IID_IMFMediaSinkPreroll
, (void **)&media_sink
->preroll
)))
1147 session
->presentation
.flags
|= SESSION_FLAG_NEEDS_PREROLL
;
1150 list_add_tail(&session
->presentation
.sinks
, &media_sink
->entry
);
1155 static unsigned int transform_node_get_stream_id(struct topo_node
*node
, BOOL output
, unsigned int index
)
1157 unsigned int *map
= output
? node
->u
.transform
.output_map
: node
->u
.transform
.input_map
;
1158 return map
? map
[index
] : index
;
1161 static HRESULT
session_set_transform_stream_info(struct topo_node
*node
)
1163 unsigned int *input_map
= NULL
, *output_map
= NULL
;
1164 unsigned int i
, input_count
, output_count
, block_alignment
;
1165 struct transform_stream
*streams
;
1166 IMFMediaType
*media_type
;
1170 hr
= IMFTransform_GetStreamCount(node
->object
.transform
, &input_count
, &output_count
);
1171 if (SUCCEEDED(hr
) && (input_count
> 1 || output_count
> 1))
1173 input_map
= heap_calloc(input_count
, sizeof(*input_map
));
1174 output_map
= heap_calloc(output_count
, sizeof(*output_map
));
1175 if (FAILED(IMFTransform_GetStreamIDs(node
->object
.transform
, input_count
, input_map
,
1176 output_count
, output_map
)))
1178 /* Assume sequential identifiers. */
1179 heap_free(input_map
);
1180 heap_free(output_map
);
1181 input_map
= output_map
= NULL
;
1187 node
->u
.transform
.input_map
= input_map
;
1188 node
->u
.transform
.output_map
= output_map
;
1190 streams
= heap_calloc(input_count
, sizeof(*streams
));
1191 for (i
= 0; i
< input_count
; ++i
)
1192 list_init(&streams
[i
].samples
);
1193 node
->u
.transform
.inputs
= streams
;
1194 node
->u
.transform
.input_count
= input_count
;
1196 streams
= heap_calloc(output_count
, sizeof(*streams
));
1197 for (i
= 0; i
< output_count
; ++i
)
1199 list_init(&streams
[i
].samples
);
1201 if (SUCCEEDED(IMFTransform_GetOutputCurrentType(node
->object
.transform
,
1202 transform_node_get_stream_id(node
, TRUE
, i
), &media_type
)))
1204 if (SUCCEEDED(IMFMediaType_GetMajorType(media_type
, &major
)) && IsEqualGUID(&major
, &MFMediaType_Audio
)
1205 && SUCCEEDED(IMFMediaType_GetUINT32(media_type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
, &block_alignment
)))
1207 streams
[i
].min_buffer_size
= block_alignment
;
1209 IMFMediaType_Release(media_type
);
1212 node
->u
.transform
.outputs
= streams
;
1213 node
->u
.transform
.output_count
= output_count
;
1219 static HRESULT
session_get_stream_sink_type(IMFStreamSink
*sink
, IMFMediaType
**media_type
)
1221 IMFMediaTypeHandler
*handler
;
1224 if (SUCCEEDED(hr
= IMFStreamSink_GetMediaTypeHandler(sink
, &handler
)))
1226 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, media_type
);
1227 IMFMediaTypeHandler_Release(handler
);
1233 static HRESULT WINAPI
node_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify
*iface
,
1234 REFIID riid
, void **obj
)
1236 if (IsEqualIID(riid
, &IID_IMFVideoSampleAllocatorNotify
) ||
1237 IsEqualIID(riid
, &IID_IUnknown
))
1240 IMFVideoSampleAllocatorNotify_AddRef(iface
);
1245 return E_NOINTERFACE
;
1248 static ULONG WINAPI
node_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify
*iface
)
1253 static ULONG WINAPI
node_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify
*iface
)
1258 static HRESULT
session_request_sample_from_node(struct media_session
*session
, IMFTopologyNode
*node
, DWORD output
);
1260 static HRESULT WINAPI
node_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify
*iface
)
1262 struct topo_node
*topo_node
= impl_node_from_IMFVideoSampleAllocatorNotify(iface
);
1263 struct session_op
*op
;
1265 if (SUCCEEDED(create_session_op(SESSION_CMD_SA_READY
, &op
)))
1267 op
->u
.sa_ready
.node_id
= topo_node
->node_id
;
1268 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &topo_node
->session
->commands_callback
, &op
->IUnknown_iface
);
1269 IUnknown_Release(&op
->IUnknown_iface
);
1275 static const IMFVideoSampleAllocatorNotifyVtbl node_sample_allocator_cb_vtbl
=
1277 node_sample_allocator_cb_QueryInterface
,
1278 node_sample_allocator_cb_AddRef
,
1279 node_sample_allocator_cb_Release
,
1280 node_sample_allocator_cb_NotifyRelease
,
1283 static HRESULT
session_append_node(struct media_session
*session
, IMFTopologyNode
*node
)
1285 struct topo_node
*topo_node
;
1286 IMFMediaSink
*media_sink
;
1287 IMFMediaType
*media_type
;
1288 IMFStreamDescriptor
*sd
;
1291 if (!(topo_node
= heap_alloc_zero(sizeof(*topo_node
))))
1292 return E_OUTOFMEMORY
;
1294 IMFTopologyNode_GetNodeType(node
, &topo_node
->type
);
1295 IMFTopologyNode_GetTopoNodeID(node
, &topo_node
->node_id
);
1296 topo_node
->node
= node
;
1297 IMFTopologyNode_AddRef(topo_node
->node
);
1298 topo_node
->session
= session
;
1300 switch (topo_node
->type
)
1302 case MF_TOPOLOGY_OUTPUT_NODE
:
1303 topo_node
->u
.sink
.notify_cb
.lpVtbl
= &node_sample_allocator_cb_vtbl
;
1305 if (FAILED(hr
= topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&topo_node
->object
.object
)))
1307 WARN("Failed to get stream sink interface, hr %#x.\n", hr
);
1311 if (FAILED(hr
= IMFStreamSink_GetMediaSink(topo_node
->object
.sink_stream
, &media_sink
)))
1314 if (SUCCEEDED(hr
= session_add_media_sink(session
, node
, media_sink
)))
1316 if (SUCCEEDED(session_get_stream_sink_type(topo_node
->object
.sink_stream
, &media_type
)))
1318 if (SUCCEEDED(MFGetService(topo_node
->object
.object
, &MR_VIDEO_ACCELERATION_SERVICE
,
1319 &IID_IMFVideoSampleAllocator
, (void **)&topo_node
->u
.sink
.allocator
)))
1321 if (FAILED(hr
= IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node
->u
.sink
.allocator
,
1324 WARN("Failed to initialize sample allocator for the stream, hr %#x.\n", hr
);
1326 IMFVideoSampleAllocator_QueryInterface(topo_node
->u
.sink
.allocator
,
1327 &IID_IMFVideoSampleAllocatorCallback
, (void **)&topo_node
->u
.sink
.allocator_cb
);
1328 IMFVideoSampleAllocatorCallback_SetCallback(topo_node
->u
.sink
.allocator_cb
,
1329 &topo_node
->u
.sink
.notify_cb
);
1331 IMFMediaType_Release(media_type
);
1334 IMFMediaSink_Release(media_sink
);
1337 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
1338 if (FAILED(IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_SOURCE
, &IID_IMFMediaSource
,
1339 (void **)&topo_node
->u
.source
.source
)))
1341 WARN("Missing MF_TOPONODE_SOURCE, hr %#x.\n", hr
);
1345 if (FAILED(hr
= session_add_media_source(session
, node
, topo_node
->u
.source
.source
)))
1348 if (FAILED(hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_STREAM_DESCRIPTOR
,
1349 &IID_IMFStreamDescriptor
, (void **)&sd
)))
1351 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#x.\n", hr
);
1355 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &topo_node
->u
.source
.stream_id
);
1356 IMFStreamDescriptor_Release(sd
);
1359 case MF_TOPOLOGY_TRANSFORM_NODE
:
1361 if (SUCCEEDED(hr
= topology_node_get_object(node
, &IID_IMFTransform
, (void **)&topo_node
->object
.transform
)))
1363 hr
= session_set_transform_stream_info(topo_node
);
1366 WARN("Failed to get IMFTransform for MFT node, hr %#x.\n", hr
);
1369 case MF_TOPOLOGY_TEE_NODE
:
1370 FIXME("Unsupported node type %d.\n", topo_node
->type
);
1378 list_add_tail(&session
->presentation
.nodes
, &topo_node
->entry
);
1380 release_topo_node(topo_node
);
1385 static HRESULT
session_collect_nodes(struct media_session
*session
)
1387 IMFTopology
*topology
= session
->presentation
.current_topology
;
1388 IMFTopologyNode
*node
;
1392 if (!list_empty(&session
->presentation
.nodes
))
1395 if (FAILED(hr
= IMFTopology_GetNodeCount(topology
, &count
)))
1398 for (i
= 0; i
< count
; ++i
)
1400 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
1402 WARN("Failed to get node %u.\n", i
);
1406 hr
= session_append_node(session
, node
);
1407 IMFTopologyNode_Release(node
);
1410 WARN("Failed to add node %u.\n", i
);
1418 static HRESULT
session_set_current_topology(struct media_session
*session
, IMFTopology
*topology
)
1420 struct media_source
*source
;
1421 DWORD caps
, object_flags
;
1422 struct media_sink
*sink
;
1423 struct topo_node
*node
;
1424 struct session_op
*op
;
1425 IMFMediaEvent
*event
;
1428 if (session
->quality_manager
)
1430 if (SUCCEEDED(create_session_op(SESSION_CMD_QM_NOTIFY_TOPOLOGY
, &op
)))
1432 op
->u
.notify_topology
.topology
= topology
;
1433 IMFTopology_AddRef(op
->u
.notify_topology
.topology
);
1434 session_submit_command(session
, op
);
1435 IUnknown_Release(&op
->IUnknown_iface
);
1439 if (FAILED(hr
= IMFTopology_CloneFrom(session
->presentation
.current_topology
, topology
)))
1441 WARN("Failed to clone topology, hr %#x.\n", hr
);
1445 session_collect_nodes(session
);
1447 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1449 if (node
->type
== MF_TOPOLOGY_TRANSFORM_NODE
)
1451 if (FAILED(hr
= IMFTransform_ProcessMessage(node
->object
.transform
,
1452 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING
, 0)))
1457 /* FIXME: attributes are all zero for now */
1458 if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime
, &GUID_NULL
, S_OK
, NULL
, &event
)))
1460 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_START_PRESENTATION_TIME
, 0);
1461 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_PRESENTATION_TIME_OFFSET
, 0);
1462 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT
, 0);
1464 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
1465 IMFMediaEvent_Release(event
);
1468 /* Update session caps. */
1469 caps
= MFSESSIONCAP_START
| MFSESSIONCAP_SEEK
| MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
|
1470 MFSESSIONCAP_DOES_NOT_USE_NETWORK
;
1472 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
1478 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source
->source
, &object_flags
)))
1480 if (!(object_flags
& MFMEDIASOURCE_DOES_NOT_USE_NETWORK
))
1481 caps
&= ~MFSESSIONCAP_DOES_NOT_USE_NETWORK
;
1482 if (!(object_flags
& MFMEDIASOURCE_CAN_SEEK
))
1483 caps
&= ~MFSESSIONCAP_SEEK
;
1486 /* Mask unsupported rate caps. */
1488 caps
&= session_get_object_rate_caps((IUnknown
*)source
->source
)
1489 | ~(MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
);
1492 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1498 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink
->sink
, &object_flags
)))
1500 if (!(object_flags
& MEDIASINK_RATELESS
))
1501 caps
&= session_get_object_rate_caps((IUnknown
*)sink
->sink
)
1502 | ~(MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
);
1506 session_set_caps(session
, caps
);
1511 static void session_set_topology(struct media_session
*session
, DWORD flags
, IMFTopology
*topology
)
1513 IMFTopology
*resolved_topology
= NULL
;
1516 /* Resolve unless claimed to be full. */
1517 if (!(flags
& MFSESSION_SETTOPOLOGY_CLEAR_CURRENT
) && topology
)
1519 if (!(flags
& MFSESSION_SETTOPOLOGY_NORESOLUTION
))
1521 hr
= session_bind_output_nodes(topology
);
1524 hr
= IMFTopoLoader_Load(session
->topo_loader
, topology
, &resolved_topology
, NULL
/* FIXME? */);
1528 topology
= resolved_topology
;
1533 if (flags
& MFSESSION_SETTOPOLOGY_CLEAR_CURRENT
)
1535 if ((topology
&& topology
== session
->presentation
.current_topology
) || !topology
)
1537 /* FIXME: stop current topology, queue next one. */
1538 session_clear_presentation(session
);
1545 else if (topology
&& flags
& MFSESSION_SETTOPOLOGY_IMMEDIATE
)
1547 session_clear_topologies(session
);
1548 session_clear_presentation(session
);
1551 session_raise_topology_set(session
, topology
, hr
);
1553 /* With no current topology set it right away, otherwise queue. */
1556 struct queued_topology
*queued_topology
;
1558 if ((queued_topology
= heap_alloc_zero(sizeof(*queued_topology
))))
1560 queued_topology
->topology
= topology
;
1561 IMFTopology_AddRef(queued_topology
->topology
);
1563 list_add_tail(&session
->topologies
, &queued_topology
->entry
);
1566 if (session
->presentation
.topo_status
== MF_TOPOSTATUS_INVALID
)
1568 hr
= session_set_current_topology(session
, topology
);
1569 session_set_topo_status(session
, hr
, MF_TOPOSTATUS_READY
);
1573 if (resolved_topology
)
1574 IMFTopology_Release(resolved_topology
);
1577 static HRESULT WINAPI
mfsession_QueryInterface(IMFMediaSession
*iface
, REFIID riid
, void **out
)
1579 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1581 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1583 if (IsEqualIID(riid
, &IID_IMFMediaSession
) ||
1584 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
1585 IsEqualIID(riid
, &IID_IUnknown
))
1587 *out
= &session
->IMFMediaSession_iface
;
1588 IMFMediaSession_AddRef(iface
);
1591 else if (IsEqualIID(riid
, &IID_IMFGetService
))
1593 *out
= &session
->IMFGetService_iface
;
1594 IMFMediaSession_AddRef(iface
);
1598 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1600 return E_NOINTERFACE
;
1603 static ULONG WINAPI
mfsession_AddRef(IMFMediaSession
*iface
)
1605 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1606 ULONG refcount
= InterlockedIncrement(&session
->refcount
);
1608 TRACE("%p, refcount %u.\n", iface
, refcount
);
1613 static ULONG WINAPI
mfsession_Release(IMFMediaSession
*iface
)
1615 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1616 ULONG refcount
= InterlockedDecrement(&session
->refcount
);
1618 TRACE("%p, refcount %u.\n", iface
, refcount
);
1622 session_clear_topologies(session
);
1623 session_clear_presentation(session
);
1624 session_clear_command_list(session
);
1625 if (session
->presentation
.current_topology
)
1626 IMFTopology_Release(session
->presentation
.current_topology
);
1627 if (session
->event_queue
)
1628 IMFMediaEventQueue_Release(session
->event_queue
);
1630 IMFPresentationClock_Release(session
->clock
);
1631 if (session
->system_time_source
)
1632 IMFPresentationTimeSource_Release(session
->system_time_source
);
1633 if (session
->clock_rate_control
)
1634 IMFRateControl_Release(session
->clock_rate_control
);
1635 if (session
->topo_loader
)
1636 IMFTopoLoader_Release(session
->topo_loader
);
1637 if (session
->quality_manager
)
1638 IMFQualityManager_Release(session
->quality_manager
);
1639 DeleteCriticalSection(&session
->cs
);
1646 static HRESULT WINAPI
mfsession_GetEvent(IMFMediaSession
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1648 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1650 TRACE("%p, %#x, %p.\n", iface
, flags
, event
);
1652 return IMFMediaEventQueue_GetEvent(session
->event_queue
, flags
, event
);
1655 static HRESULT WINAPI
mfsession_BeginGetEvent(IMFMediaSession
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
1657 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1659 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1661 return IMFMediaEventQueue_BeginGetEvent(session
->event_queue
, callback
, state
);
1664 static HRESULT WINAPI
mfsession_EndGetEvent(IMFMediaSession
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
1666 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1668 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1670 return IMFMediaEventQueue_EndGetEvent(session
->event_queue
, result
, event
);
1673 static HRESULT WINAPI
mfsession_QueueEvent(IMFMediaSession
*iface
, MediaEventType event_type
, REFGUID ext_type
,
1674 HRESULT hr
, const PROPVARIANT
*value
)
1676 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1678 TRACE("%p, %d, %s, %#x, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1680 return IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, event_type
, ext_type
, hr
, value
);
1683 static HRESULT WINAPI
mfsession_SetTopology(IMFMediaSession
*iface
, DWORD flags
, IMFTopology
*topology
)
1685 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1686 struct session_op
*op
;
1687 WORD node_count
= 0;
1690 TRACE("%p, %#x, %p.\n", iface
, flags
, topology
);
1694 if (FAILED(IMFTopology_GetNodeCount(topology
, &node_count
)) || node_count
== 0)
1695 return E_INVALIDARG
;
1698 if (FAILED(hr
= create_session_op(SESSION_CMD_SET_TOPOLOGY
, &op
)))
1701 op
->u
.set_topology
.flags
= flags
;
1702 op
->u
.set_topology
.topology
= topology
;
1703 if (op
->u
.set_topology
.topology
)
1704 IMFTopology_AddRef(op
->u
.set_topology
.topology
);
1706 hr
= session_submit_command(session
, op
);
1707 IUnknown_Release(&op
->IUnknown_iface
);
1712 static HRESULT WINAPI
mfsession_ClearTopologies(IMFMediaSession
*iface
)
1714 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1716 TRACE("%p.\n", iface
);
1718 return session_submit_simple_command(session
, SESSION_CMD_CLEAR_TOPOLOGIES
);
1721 static HRESULT WINAPI
mfsession_Start(IMFMediaSession
*iface
, const GUID
*format
, const PROPVARIANT
*start_position
)
1723 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1724 struct session_op
*op
;
1727 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(format
), start_position
);
1729 if (!start_position
)
1732 if (FAILED(hr
= create_session_op(SESSION_CMD_START
, &op
)))
1735 op
->u
.start
.time_format
= format
? *format
: GUID_NULL
;
1736 hr
= PropVariantCopy(&op
->u
.start
.start_position
, start_position
);
1739 hr
= session_submit_command(session
, op
);
1741 IUnknown_Release(&op
->IUnknown_iface
);
1745 static HRESULT WINAPI
mfsession_Pause(IMFMediaSession
*iface
)
1747 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1749 TRACE("%p.\n", iface
);
1751 return session_submit_simple_command(session
, SESSION_CMD_PAUSE
);
1754 static HRESULT WINAPI
mfsession_Stop(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_STOP
);
1763 static HRESULT WINAPI
mfsession_Close(IMFMediaSession
*iface
)
1765 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1767 TRACE("%p.\n", iface
);
1769 return session_submit_simple_command(session
, SESSION_CMD_CLOSE
);
1772 static HRESULT WINAPI
mfsession_Shutdown(IMFMediaSession
*iface
)
1774 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1777 TRACE("%p.\n", iface
);
1779 EnterCriticalSection(&session
->cs
);
1780 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1782 session
->state
= SESSION_STATE_SHUT_DOWN
;
1783 IMFMediaEventQueue_Shutdown(session
->event_queue
);
1784 if (session
->quality_manager
)
1785 IMFQualityManager_Shutdown(session
->quality_manager
);
1786 MFShutdownObject((IUnknown
*)session
->clock
);
1787 IMFPresentationClock_Release(session
->clock
);
1788 session
->clock
= NULL
;
1789 session_clear_presentation(session
);
1790 session_clear_command_list(session
);
1792 LeaveCriticalSection(&session
->cs
);
1797 static HRESULT WINAPI
mfsession_GetClock(IMFMediaSession
*iface
, IMFClock
**clock
)
1799 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1802 TRACE("%p, %p.\n", iface
, clock
);
1804 EnterCriticalSection(&session
->cs
);
1805 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1807 *clock
= (IMFClock
*)session
->clock
;
1808 IMFClock_AddRef(*clock
);
1810 LeaveCriticalSection(&session
->cs
);
1815 static HRESULT WINAPI
mfsession_GetSessionCapabilities(IMFMediaSession
*iface
, DWORD
*caps
)
1817 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1820 TRACE("%p, %p.\n", iface
, caps
);
1825 EnterCriticalSection(&session
->cs
);
1826 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1827 *caps
= session
->caps
;
1828 LeaveCriticalSection(&session
->cs
);
1833 static HRESULT WINAPI
mfsession_GetFullTopology(IMFMediaSession
*iface
, DWORD flags
, TOPOID id
, IMFTopology
**topology
)
1835 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1836 struct queued_topology
*queued
;
1840 TRACE("%p, %#x, %s, %p.\n", iface
, flags
, wine_dbgstr_longlong(id
), topology
);
1844 EnterCriticalSection(&session
->cs
);
1846 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1848 if (flags
& MFSESSION_GETFULLTOPOLOGY_CURRENT
)
1850 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
1851 *topology
= session
->presentation
.current_topology
;
1853 hr
= MF_E_INVALIDREQUEST
;
1857 LIST_FOR_EACH_ENTRY(queued
, &session
->topologies
, struct queued_topology
, entry
)
1859 if (SUCCEEDED(IMFTopology_GetTopologyID(queued
->topology
, &topo_id
)) && topo_id
== id
)
1861 *topology
= queued
->topology
;
1868 IMFTopology_AddRef(*topology
);
1871 LeaveCriticalSection(&session
->cs
);
1876 static const IMFMediaSessionVtbl mfmediasessionvtbl
=
1878 mfsession_QueryInterface
,
1882 mfsession_BeginGetEvent
,
1883 mfsession_EndGetEvent
,
1884 mfsession_QueueEvent
,
1885 mfsession_SetTopology
,
1886 mfsession_ClearTopologies
,
1893 mfsession_GetSessionCapabilities
,
1894 mfsession_GetFullTopology
,
1897 static HRESULT WINAPI
session_get_service_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
1899 struct media_session
*session
= impl_from_IMFGetService(iface
);
1900 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
1903 static ULONG WINAPI
session_get_service_AddRef(IMFGetService
*iface
)
1905 struct media_session
*session
= impl_from_IMFGetService(iface
);
1906 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
1909 static ULONG WINAPI
session_get_service_Release(IMFGetService
*iface
)
1911 struct media_session
*session
= impl_from_IMFGetService(iface
);
1912 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
1915 static HRESULT
session_get_video_render_service(struct media_session
*session
, REFGUID service
,
1916 REFIID riid
, void **obj
)
1918 IMFStreamSink
*stream_sink
;
1919 IMFTopologyNode
*node
;
1920 IMFCollection
*nodes
;
1924 HRESULT hr
= E_FAIL
;
1926 /* Use first sink to support IMFVideoRenderer. */
1927 if (session
->presentation
.current_topology
)
1929 if (SUCCEEDED(IMFTopology_GetOutputNodeCollection(session
->presentation
.current_topology
,
1932 while (IMFCollection_GetElement(nodes
, i
++, (IUnknown
**)&node
) == S_OK
)
1934 if (SUCCEEDED(topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
1936 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink
, &sink
)))
1938 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
, &IID_IMFVideoRenderer
, (void **)&vr
)))
1940 if (FAILED(hr
= MFGetService(vr
, service
, riid
, obj
)))
1941 WARN("Failed to get service from video renderer %#x.\n", hr
);
1942 IUnknown_Release(vr
);
1945 IMFStreamSink_Release(stream_sink
);
1948 IMFTopologyNode_Release(node
);
1954 IMFCollection_Release(nodes
);
1961 static HRESULT WINAPI
session_get_service_GetService(IMFGetService
*iface
, REFGUID service
, REFIID riid
, void **obj
)
1963 struct media_session
*session
= impl_from_IMFGetService(iface
);
1966 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
1970 EnterCriticalSection(&session
->cs
);
1971 if (FAILED(hr
= session_is_shut_down(session
)))
1974 else if (IsEqualGUID(service
, &MF_RATE_CONTROL_SERVICE
))
1976 if (IsEqualIID(riid
, &IID_IMFRateSupport
))
1978 *obj
= &session
->IMFRateSupport_iface
;
1980 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
1982 *obj
= &session
->IMFRateControl_iface
;
1988 IUnknown_AddRef((IUnknown
*)*obj
);
1990 else if (IsEqualGUID(service
, &MF_LOCAL_MFT_REGISTRATION_SERVICE
))
1992 hr
= IMFLocalMFTRegistration_QueryInterface(&local_mft_registration
, riid
, obj
);
1994 else if (IsEqualGUID(service
, &MF_TOPONODE_ATTRIBUTE_EDITOR_SERVICE
))
1996 *obj
= &session
->IMFTopologyNodeAttributeEditor_iface
;
1997 IUnknown_AddRef((IUnknown
*)*obj
);
1999 else if (IsEqualGUID(service
, &MR_VIDEO_RENDER_SERVICE
))
2001 hr
= session_get_video_render_service(session
, service
, riid
, obj
);
2004 FIXME("Unsupported service %s.\n", debugstr_guid(service
));
2006 LeaveCriticalSection(&session
->cs
);
2011 static const IMFGetServiceVtbl session_get_service_vtbl
=
2013 session_get_service_QueryInterface
,
2014 session_get_service_AddRef
,
2015 session_get_service_Release
,
2016 session_get_service_GetService
,
2019 static HRESULT WINAPI
session_commands_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2021 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
2022 IsEqualIID(riid
, &IID_IUnknown
))
2025 IMFAsyncCallback_AddRef(iface
);
2029 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2031 return E_NOINTERFACE
;
2034 static ULONG WINAPI
session_commands_callback_AddRef(IMFAsyncCallback
*iface
)
2036 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2037 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2040 static ULONG WINAPI
session_commands_callback_Release(IMFAsyncCallback
*iface
)
2042 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2043 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2046 static HRESULT WINAPI
session_commands_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2051 static HRESULT WINAPI
session_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
2053 struct session_op
*op
= impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result
));
2054 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2055 struct topo_node
*topo_node
;
2056 IMFTopologyNode
*upstream_node
;
2057 unsigned int upstream_output
;
2059 EnterCriticalSection(&session
->cs
);
2061 switch (op
->command
)
2063 case SESSION_CMD_CLEAR_TOPOLOGIES
:
2064 session_clear_topologies(session
);
2065 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionTopologiesCleared
, &GUID_NULL
,
2067 session_command_complete(session
);
2069 case SESSION_CMD_SET_TOPOLOGY
:
2070 session_set_topology(session
, op
->u
.set_topology
.flags
, op
->u
.set_topology
.topology
);
2071 session_command_complete(session
);
2073 case SESSION_CMD_START
:
2074 session_start(session
, &op
->u
.start
.time_format
, &op
->u
.start
.start_position
);
2076 case SESSION_CMD_PAUSE
:
2077 session_pause(session
);
2079 case SESSION_CMD_STOP
:
2080 session_stop(session
);
2082 case SESSION_CMD_CLOSE
:
2083 session_close(session
);
2085 case SESSION_CMD_QM_NOTIFY_TOPOLOGY
:
2086 IMFQualityManager_NotifyTopology(session
->quality_manager
, op
->u
.notify_topology
.topology
);
2087 session_command_complete(session
);
2089 case SESSION_CMD_SA_READY
:
2090 topo_node
= session_get_node_by_id(session
, op
->u
.sa_ready
.node_id
);
2092 if (topo_node
->u
.sink
.requests
)
2094 if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node
->node
, 0, &upstream_node
, &upstream_output
)))
2096 session_request_sample_from_node(session
, upstream_node
, upstream_output
);
2097 IMFTopologyNode_Release(upstream_node
);
2105 LeaveCriticalSection(&session
->cs
);
2110 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl
=
2112 session_commands_callback_QueryInterface
,
2113 session_commands_callback_AddRef
,
2114 session_commands_callback_Release
,
2115 session_commands_callback_GetParameters
,
2116 session_commands_callback_Invoke
,
2119 static HRESULT WINAPI
session_events_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2121 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
2122 IsEqualIID(riid
, &IID_IUnknown
))
2125 IMFAsyncCallback_AddRef(iface
);
2129 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2131 return E_NOINTERFACE
;
2134 static ULONG WINAPI
session_events_callback_AddRef(IMFAsyncCallback
*iface
)
2136 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
2137 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2140 static ULONG WINAPI
session_events_callback_Release(IMFAsyncCallback
*iface
)
2142 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
2143 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2146 static HRESULT WINAPI
session_events_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2151 static HRESULT
session_add_media_stream(struct media_session
*session
, IMFMediaSource
*source
, IMFMediaStream
*stream
)
2153 struct topo_node
*node
;
2154 IMFStreamDescriptor
*sd
;
2155 DWORD stream_id
= 0;
2158 if (FAILED(hr
= IMFMediaStream_GetStreamDescriptor(stream
, &sd
)))
2161 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &stream_id
);
2162 IMFStreamDescriptor_Release(sd
);
2166 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2168 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->u
.source
.source
== source
2169 && node
->u
.source
.stream_id
== stream_id
)
2171 if (node
->object
.source_stream
)
2173 WARN("Node already has stream set.\n");
2177 node
->object
.source_stream
= stream
;
2178 IMFMediaStream_AddRef(node
->object
.source_stream
);
2186 static BOOL
session_is_source_nodes_state(struct media_session
*session
, enum object_state state
)
2188 struct media_source
*source
;
2189 struct topo_node
*node
;
2191 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2193 if (source
->state
!= state
)
2197 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2199 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->state
!= state
)
2206 static BOOL
session_is_output_nodes_state(struct media_session
*session
, enum object_state state
)
2208 struct topo_node
*node
;
2210 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2212 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->state
!= state
)
2219 static enum object_state
session_get_object_state_for_event(MediaEventType event
)
2223 case MESourceStarted
:
2224 case MEStreamStarted
:
2225 case MEStreamSinkStarted
:
2226 return OBJ_STATE_STARTED
;
2227 case MESourcePaused
:
2228 case MEStreamPaused
:
2229 case MEStreamSinkPaused
:
2230 return OBJ_STATE_PAUSED
;
2231 case MESourceStopped
:
2232 case MEStreamStopped
:
2233 case MEStreamSinkStopped
:
2234 return OBJ_STATE_STOPPED
;
2235 case MEStreamSinkPrerolled
:
2236 return OBJ_STATE_PREROLLED
;
2238 return OBJ_STATE_INVALID
;
2242 static void session_set_consumed_clock(IUnknown
*object
, IMFPresentationClock
*clock
)
2244 IMFClockConsumer
*consumer
;
2246 if (SUCCEEDED(IUnknown_QueryInterface(object
, &IID_IMFClockConsumer
, (void **)&consumer
)))
2248 IMFClockConsumer_SetPresentationClock(consumer
, clock
);
2249 IMFClockConsumer_Release(consumer
);
2253 static void session_set_presentation_clock(struct media_session
*session
)
2255 IMFPresentationTimeSource
*time_source
= NULL
;
2256 struct media_source
*source
;
2257 struct media_sink
*sink
;
2258 struct topo_node
*node
;
2261 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2263 if (node
->type
== MF_TOPOLOGY_TRANSFORM_NODE
)
2264 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_NOTIFY_START_OF_STREAM
, 0);
2267 if (!(session
->presentation
.flags
& SESSION_FLAG_PRESENTATION_CLOCK_SET
))
2269 /* Attempt to get time source from the sinks. */
2270 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2272 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFPresentationTimeSource
,
2273 (void **)&time_source
)))
2279 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, time_source
);
2280 IMFPresentationTimeSource_Release(time_source
);
2283 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, session
->system_time_source
);
2286 WARN("Failed to set time source, hr %#x.\n", hr
);
2288 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2290 if (node
->type
!= MF_TOPOLOGY_OUTPUT_NODE
)
2293 if (FAILED(hr
= IMFStreamSink_BeginGetEvent(node
->object
.sink_stream
, &session
->events_callback
,
2294 node
->object
.object
)))
2296 WARN("Failed to subscribe to stream sink events, hr %#x.\n", hr
);
2300 /* Set clock for all topology nodes. */
2301 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2303 session_set_consumed_clock((IUnknown
*)source
->source
, session
->clock
);
2306 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2308 if (sink
->event_generator
&& FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(sink
->event_generator
,
2309 &session
->events_callback
, (IUnknown
*)sink
->event_generator
)))
2311 WARN("Failed to subscribe to sink events, hr %#x.\n", hr
);
2314 if (FAILED(hr
= IMFMediaSink_SetPresentationClock(sink
->sink
, session
->clock
)))
2315 WARN("Failed to set presentation clock for the sink, hr %#x.\n", hr
);
2318 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2320 if (node
->type
!= MF_TOPOLOGY_TRANSFORM_NODE
)
2323 session_set_consumed_clock(node
->object
.object
, session
->clock
);
2326 session
->presentation
.flags
|= SESSION_FLAG_PRESENTATION_CLOCK_SET
;
2330 static HRESULT
session_start_clock(struct media_session
*session
)
2332 LONGLONG start_offset
= 0;
2335 if (IsEqualGUID(&session
->presentation
.time_format
, &GUID_NULL
))
2337 if (session
->presentation
.start_position
.vt
== VT_EMPTY
)
2338 start_offset
= PRESENTATION_CURRENT_POSITION
;
2339 else if (session
->presentation
.start_position
.vt
== VT_I8
)
2340 start_offset
= session
->presentation
.start_position
.hVal
.QuadPart
;
2342 FIXME("Unhandled position type %d.\n", session
->presentation
.start_position
.vt
);
2345 FIXME("Unhandled time format %s.\n", debugstr_guid(&session
->presentation
.time_format
));
2347 if (FAILED(hr
= IMFPresentationClock_Start(session
->clock
, start_offset
)))
2348 WARN("Failed to start session clock, hr %#x.\n", hr
);
2353 static struct topo_node
*session_get_node_object(struct media_session
*session
, IUnknown
*object
,
2354 MF_TOPOLOGY_TYPE node_type
)
2356 struct topo_node
*node
= NULL
;
2358 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2360 if (node
->type
== node_type
&& object
== node
->object
.object
)
2367 static BOOL
session_set_node_object_state(struct media_session
*session
, IUnknown
*object
,
2368 MF_TOPOLOGY_TYPE node_type
, enum object_state state
)
2370 struct topo_node
*node
;
2371 BOOL changed
= FALSE
;
2373 if ((node
= session_get_node_object(session
, object
, node_type
)))
2375 changed
= node
->state
!= state
;
2376 node
->state
= state
;
2382 static void session_set_source_object_state(struct media_session
*session
, IUnknown
*object
,
2383 MediaEventType event_type
)
2385 IMFStreamSink
*stream_sink
;
2386 struct media_source
*src
;
2387 struct media_sink
*sink
;
2388 enum object_state state
;
2389 struct topo_node
*node
;
2390 unsigned int i
, count
;
2391 BOOL changed
= FALSE
;
2394 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2399 case MESourceStarted
:
2400 case MESourcePaused
:
2401 case MESourceStopped
:
2403 LIST_FOR_EACH_ENTRY(src
, &session
->presentation
.sources
, struct media_source
, entry
)
2405 if (object
== (IUnknown
*)src
->source
)
2407 changed
= src
->state
!= state
;
2413 case MEStreamStarted
:
2414 case MEStreamPaused
:
2415 case MEStreamStopped
:
2417 changed
= session_set_node_object_state(session
, object
, MF_TOPOLOGY_SOURCESTREAM_NODE
, state
);
2425 switch (session
->state
)
2427 case SESSION_STATE_STARTING_SOURCES
:
2428 if (!session_is_source_nodes_state(session
, OBJ_STATE_STARTED
))
2431 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_STARTED_SOURCE
);
2433 session_set_presentation_clock(session
);
2435 if (session
->presentation
.flags
& SESSION_FLAG_NEEDS_PREROLL
)
2437 MFTIME preroll_time
= 0;
2439 if (session
->presentation
.start_position
.vt
== VT_I8
)
2440 preroll_time
= session
->presentation
.start_position
.hVal
.QuadPart
;
2442 /* Mark stream sinks without prerolling support as PREROLLED to keep state test logic generic. */
2443 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2447 /* FIXME: abort and enter error state on failure. */
2448 if (FAILED(hr
= IMFMediaSinkPreroll_NotifyPreroll(sink
->preroll
, preroll_time
)))
2449 WARN("Preroll notification failed, hr %#x.\n", hr
);
2453 if (SUCCEEDED(IMFMediaSink_GetStreamSinkCount(sink
->sink
, &count
)))
2455 for (i
= 0; i
< count
; ++i
)
2457 if (SUCCEEDED(IMFMediaSink_GetStreamSinkByIndex(sink
->sink
, i
, &stream_sink
)))
2459 session_set_node_object_state(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
,
2460 OBJ_STATE_PREROLLED
);
2461 IMFStreamSink_Release(stream_sink
);
2467 session
->state
= SESSION_STATE_PREROLLING_SINKS
;
2469 else if (SUCCEEDED(session_start_clock(session
)))
2470 session
->state
= SESSION_STATE_STARTING_SINKS
;
2473 case SESSION_STATE_PAUSING_SOURCES
:
2474 if (!session_is_source_nodes_state(session
, OBJ_STATE_PAUSED
))
2477 session_set_paused(session
, S_OK
);
2479 case SESSION_STATE_STOPPING_SOURCES
:
2480 if (!session_is_source_nodes_state(session
, OBJ_STATE_STOPPED
))
2483 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2487 case MF_TOPOLOGY_OUTPUT_NODE
:
2488 IMFStreamSink_Flush(node
->object
.sink_stream
);
2490 case MF_TOPOLOGY_TRANSFORM_NODE
:
2491 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_COMMAND_FLUSH
, 0);
2498 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
2500 if (session
->presentation
.flags
& SESSION_FLAG_FINALIZE_SINKS
)
2501 session_finalize_sinks(session
);
2503 session_set_stopped(session
, S_OK
);
2511 static void session_set_sink_stream_state(struct media_session
*session
, IMFStreamSink
*stream
,
2512 MediaEventType event_type
)
2514 struct media_source
*source
;
2515 enum object_state state
;
2519 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2522 if (!(changed
= session_set_node_object_state(session
, (IUnknown
*)stream
, MF_TOPOLOGY_OUTPUT_NODE
, state
)))
2525 switch (session
->state
)
2527 case SESSION_STATE_PREROLLING_SINKS
:
2528 if (!session_is_output_nodes_state(session
, OBJ_STATE_PREROLLED
))
2531 if (SUCCEEDED(session_start_clock(session
)))
2532 session
->state
= SESSION_STATE_STARTING_SINKS
;
2534 case SESSION_STATE_STARTING_SINKS
:
2535 if (!session_is_output_nodes_state(session
, OBJ_STATE_STARTED
))
2538 session_set_started(session
);
2540 case SESSION_STATE_PAUSING_SINKS
:
2541 if (!session_is_output_nodes_state(session
, OBJ_STATE_PAUSED
))
2544 session
->state
= SESSION_STATE_PAUSING_SOURCES
;
2546 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2548 if (FAILED(hr
= IMFMediaSource_Pause(source
->source
)))
2553 session_set_paused(session
, hr
);
2556 case SESSION_STATE_STOPPING_SINKS
:
2557 if (!session_is_output_nodes_state(session
, OBJ_STATE_STOPPED
))
2560 session
->state
= SESSION_STATE_STOPPING_SOURCES
;
2562 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2564 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
)
2565 IMFMediaSource_Stop(source
->source
);
2566 else if (FAILED(hr
= IMFMediaSource_Stop(source
->source
)))
2570 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
|| FAILED(hr
))
2571 session_set_stopped(session
, hr
);
2579 static struct sample
*transform_create_sample(IMFSample
*sample
)
2581 struct sample
*sample_entry
= heap_alloc_zero(sizeof(*sample_entry
));
2585 sample_entry
->sample
= sample
;
2586 if (sample_entry
->sample
)
2587 IMFSample_AddRef(sample_entry
->sample
);
2590 return sample_entry
;
2593 static HRESULT
transform_get_external_output_sample(const struct media_session
*session
, struct topo_node
*transform
,
2594 unsigned int output_index
, const MFT_OUTPUT_STREAM_INFO
*stream_info
, IMFSample
**sample
)
2596 unsigned int buffer_size
, downstream_input
;
2597 IMFTopologyNode
*downstream_node
;
2598 IMFMediaBuffer
*buffer
= NULL
;
2599 struct topo_node
*topo_node
;
2603 if (FAILED(IMFTopologyNode_GetOutput(transform
->node
, output_index
, &downstream_node
, &downstream_input
)))
2605 WARN("Failed to get connected node for output %u.\n", output_index
);
2606 return MF_E_UNEXPECTED
;
2609 IMFTopologyNode_GetTopoNodeID(downstream_node
, &node_id
);
2610 IMFTopologyNode_Release(downstream_node
);
2612 topo_node
= session_get_node_by_id(session
, node_id
);
2614 if (topo_node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& topo_node
->u
.sink
.allocator
)
2616 hr
= IMFVideoSampleAllocator_AllocateSample(topo_node
->u
.sink
.allocator
, sample
);
2620 buffer_size
= max(stream_info
->cbSize
, transform
->u
.transform
.outputs
[output_index
].min_buffer_size
);
2622 hr
= MFCreateAlignedMemoryBuffer(buffer_size
, stream_info
->cbAlignment
, &buffer
);
2624 hr
= MFCreateSample(sample
);
2627 hr
= IMFSample_AddBuffer(*sample
, buffer
);
2630 IMFMediaBuffer_Release(buffer
);
2636 static HRESULT
transform_node_pull_samples(const struct media_session
*session
, struct topo_node
*node
)
2638 MFT_OUTPUT_STREAM_INFO stream_info
;
2639 MFT_OUTPUT_DATA_BUFFER
*buffers
;
2640 struct sample
*queued_sample
;
2643 HRESULT hr
= E_UNEXPECTED
;
2645 if (!(buffers
= heap_calloc(node
->u
.transform
.output_count
, sizeof(*buffers
))))
2646 return E_OUTOFMEMORY
;
2648 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
2650 buffers
[i
].dwStreamID
= transform_node_get_stream_id(node
, TRUE
, i
);
2651 buffers
[i
].pSample
= NULL
;
2652 buffers
[i
].dwStatus
= 0;
2653 buffers
[i
].pEvents
= NULL
;
2655 memset(&stream_info
, 0, sizeof(stream_info
));
2656 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(node
->object
.transform
, buffers
[i
].dwStreamID
, &stream_info
)))
2659 if (!(stream_info
.dwFlags
& (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
| MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES
)))
2661 if (FAILED(hr
= transform_get_external_output_sample(session
, node
, i
, &stream_info
, &buffers
[i
].pSample
)))
2667 hr
= IMFTransform_ProcessOutput(node
->object
.transform
, 0, node
->u
.transform
.output_count
, buffers
, &status
);
2669 /* Collect returned samples for all streams. */
2670 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
2672 if (buffers
[i
].pEvents
)
2673 IMFCollection_Release(buffers
[i
].pEvents
);
2675 if (SUCCEEDED(hr
) && !(buffers
[i
].dwStatus
& MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE
))
2677 if (session
->quality_manager
)
2678 IMFQualityManager_NotifyProcessOutput(session
->quality_manager
, node
->node
, i
, buffers
[i
].pSample
);
2680 queued_sample
= transform_create_sample(buffers
[i
].pSample
);
2681 list_add_tail(&node
->u
.transform
.outputs
[i
].samples
, &queued_sample
->entry
);
2684 if (buffers
[i
].pSample
)
2685 IMFSample_Release(buffers
[i
].pSample
);
2693 static void session_deliver_sample_to_node(struct media_session
*session
, IMFTopologyNode
*node
, unsigned int input
,
2696 struct sample
*sample_entry
, *sample_entry2
;
2697 DWORD stream_id
, downstream_input
;
2698 IMFTopologyNode
*downstream_node
;
2699 struct topo_node
*topo_node
;
2700 MF_TOPOLOGY_TYPE node_type
;
2706 if (session
->quality_manager
)
2707 IMFQualityManager_NotifyProcessInput(session
->quality_manager
, node
, input
, sample
);
2709 IMFTopologyNode_GetNodeType(node
, &node_type
);
2710 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
2712 topo_node
= session_get_node_by_id(session
, node_id
);
2716 case MF_TOPOLOGY_OUTPUT_NODE
:
2719 if (topo_node
->u
.sink
.requests
)
2721 if (FAILED(hr
= IMFStreamSink_ProcessSample(topo_node
->object
.sink_stream
, sample
)))
2722 WARN("Stream sink failed to process sample, hr %#x.\n", hr
);
2723 topo_node
->u
.sink
.requests
--;
2726 else if (FAILED(hr
= IMFStreamSink_PlaceMarker(topo_node
->object
.sink_stream
, MFSTREAMSINK_MARKER_ENDOFSEGMENT
,
2729 WARN("Failed to place sink marker, hr %#x.\n", hr
);
2732 case MF_TOPOLOGY_TRANSFORM_NODE
:
2734 transform_node_pull_samples(session
, topo_node
);
2736 sample_entry
= transform_create_sample(sample
);
2737 list_add_tail(&topo_node
->u
.transform
.inputs
[input
].samples
, &sample_entry
->entry
);
2739 for (i
= 0; i
< topo_node
->u
.transform
.input_count
; ++i
)
2741 stream_id
= transform_node_get_stream_id(topo_node
, FALSE
, i
);
2742 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.inputs
[i
].samples
,
2743 struct sample
, entry
)
2745 if (sample_entry
->sample
)
2747 if ((hr
= IMFTransform_ProcessInput(topo_node
->object
.transform
, stream_id
,
2748 sample_entry
->sample
, 0)) == MF_E_NOTACCEPTING
)
2751 WARN("Failed to process input for stream %u/%u, hr %#x.\n", i
, stream_id
, hr
);
2752 transform_release_sample(sample_entry
);
2756 transform_stream_drop_samples(&topo_node
->u
.transform
.inputs
[i
]);
2764 if (FAILED(hr
= IMFTransform_ProcessMessage(topo_node
->object
.transform
, MFT_MESSAGE_COMMAND_DRAIN
, 0)))
2765 WARN("Drain command failed for transform, hr %#x.\n", hr
);
2768 transform_node_pull_samples(session
, topo_node
);
2770 /* Remaining unprocessed input has been discarded, now queue markers for every output. */
2773 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
2775 if ((sample_entry
= transform_create_sample(NULL
)))
2776 list_add_tail(&topo_node
->u
.transform
.outputs
[i
].samples
, &sample_entry
->entry
);
2780 /* Push down all available output. */
2781 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
2783 if (FAILED(IMFTopologyNode_GetOutput(node
, i
, &downstream_node
, &downstream_input
)))
2785 WARN("Failed to get connected node for output %u.\n", i
);
2789 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.outputs
[i
].samples
,
2790 struct sample
, entry
)
2792 if (!topo_node
->u
.transform
.outputs
[i
].requests
)
2795 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample_entry
->sample
);
2796 topo_node
->u
.transform
.outputs
[i
].requests
--;
2798 transform_release_sample(sample_entry
);
2801 IMFTopologyNode_Release(downstream_node
);
2805 case MF_TOPOLOGY_TEE_NODE
:
2806 FIXME("Unhandled downstream node type %d.\n", node_type
);
2813 static HRESULT
session_request_sample_from_node(struct media_session
*session
, IMFTopologyNode
*node
, DWORD output
)
2815 IMFTopologyNode
*downstream_node
, *upstream_node
;
2816 unsigned int downstream_input
, upstream_output
;
2817 struct topo_node
*topo_node
;
2818 MF_TOPOLOGY_TYPE node_type
;
2819 struct sample
*sample
;
2823 IMFTopologyNode_GetNodeType(node
, &node_type
);
2824 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
2826 topo_node
= session_get_node_by_id(session
, node_id
);
2830 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
2831 if (FAILED(hr
= IMFMediaStream_RequestSample(topo_node
->object
.source_stream
, NULL
)))
2832 WARN("Sample request failed, hr %#x.\n", hr
);
2834 case MF_TOPOLOGY_TRANSFORM_NODE
:
2836 if (list_empty(&topo_node
->u
.transform
.outputs
[output
].samples
))
2838 /* Forward request to upstream node. */
2839 if (SUCCEEDED(hr
= IMFTopologyNode_GetInput(node
, 0 /* FIXME */, &upstream_node
, &upstream_output
)))
2841 if (SUCCEEDED(hr
= session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
2842 topo_node
->u
.transform
.outputs
[output
].requests
++;
2843 IMFTopologyNode_Release(upstream_node
);
2848 if (SUCCEEDED(hr
= IMFTopologyNode_GetOutput(node
, output
, &downstream_node
, &downstream_input
)))
2850 sample
= LIST_ENTRY(list_head(&topo_node
->u
.transform
.outputs
[output
].samples
), struct sample
, entry
);
2851 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample
->sample
);
2852 transform_release_sample(sample
);
2853 IMFTopologyNode_Release(downstream_node
);
2858 case MF_TOPOLOGY_TEE_NODE
:
2859 FIXME("Unhandled upstream node type %d.\n", node_type
);
2867 static void session_request_sample(struct media_session
*session
, IMFStreamSink
*sink_stream
)
2869 struct topo_node
*sink_node
= NULL
, *node
;
2870 IMFTopologyNode
*upstream_node
;
2871 DWORD upstream_output
;
2874 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2876 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink_stream
)
2886 if (FAILED(hr
= IMFTopologyNode_GetInput(sink_node
->node
, 0, &upstream_node
, &upstream_output
)))
2888 WARN("Failed to get upstream node connection, hr %#x.\n", hr
);
2892 if (SUCCEEDED(session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
2893 sink_node
->u
.sink
.requests
++;
2894 IMFTopologyNode_Release(upstream_node
);
2897 static void session_deliver_sample(struct media_session
*session
, IMFMediaStream
*stream
, const PROPVARIANT
*value
)
2899 struct topo_node
*source_node
= NULL
, *node
;
2900 IMFTopologyNode
*downstream_node
;
2901 DWORD downstream_input
;
2904 if (value
&& (value
->vt
!= VT_UNKNOWN
|| !value
->punkVal
))
2906 WARN("Unexpected value type %d.\n", value
->vt
);
2910 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2912 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->object
.source_stream
== stream
)
2923 source_node
->flags
|= TOPO_NODE_END_OF_STREAM
;
2925 if (FAILED(hr
= IMFTopologyNode_GetOutput(source_node
->node
, 0, &downstream_node
, &downstream_input
)))
2927 WARN("Failed to get downstream node connection, hr %#x.\n", hr
);
2931 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, value
? (IMFSample
*)value
->punkVal
: NULL
);
2932 IMFTopologyNode_Release(downstream_node
);
2935 static void session_sink_invalidated(struct media_session
*session
, IMFMediaEvent
*event
, IMFStreamSink
*sink
)
2937 struct topo_node
*node
, *sink_node
= NULL
;
2940 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2942 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink
)
2954 if (FAILED(hr
= MFCreateMediaEvent(MESinkInvalidated
, &GUID_NULL
, S_OK
, NULL
, &event
)))
2955 WARN("Failed to create event, hr %#x.\n", hr
);
2961 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_OUTPUT_NODE
, sink_node
->node_id
);
2962 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
2964 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
2967 static BOOL
session_nodes_is_mask_set(struct media_session
*session
, MF_TOPOLOGY_TYPE node_type
, unsigned int flags
)
2969 struct media_source
*source
;
2970 struct topo_node
*node
;
2972 if (node_type
== MF_TOPOLOGY_MAX
)
2974 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2976 if ((source
->flags
& flags
) != flags
)
2982 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2984 if (node
->type
== node_type
&& (node
->flags
& flags
) != flags
)
2992 static void session_raise_end_of_presentation(struct media_session
*session
)
2994 if (!(session_nodes_is_mask_set(session
, MF_TOPOLOGY_SOURCESTREAM_NODE
, TOPO_NODE_END_OF_STREAM
)))
2997 if (!(session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
))
2999 if (session_nodes_is_mask_set(session
, MF_TOPOLOGY_MAX
, SOURCE_FLAG_END_OF_PRESENTATION
))
3001 session
->presentation
.flags
|= SESSION_FLAG_END_OF_PRESENTATION
;
3002 session_push_back_command(session
, SESSION_CMD_END
);
3003 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MEEndOfPresentation
, &GUID_NULL
, S_OK
, NULL
);
3008 static void session_handle_end_of_stream(struct media_session
*session
, IMFMediaStream
*stream
)
3010 struct topo_node
*node
;
3012 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream
, MF_TOPOLOGY_SOURCESTREAM_NODE
))
3013 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
3018 session_deliver_sample(session
, stream
, NULL
);
3020 session_raise_end_of_presentation(session
);
3023 static void session_handle_end_of_presentation(struct media_session
*session
, IMFMediaSource
*object
)
3025 struct media_source
*source
;
3027 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3029 if (source
->source
== object
)
3031 if (!(source
->flags
& SOURCE_FLAG_END_OF_PRESENTATION
))
3033 source
->flags
|= SOURCE_FLAG_END_OF_PRESENTATION
;
3034 session_raise_end_of_presentation(session
);
3042 static void session_sink_stream_marker(struct media_session
*session
, IMFStreamSink
*stream_sink
)
3044 struct topo_node
*node
;
3046 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
))
3047 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
3052 node
->flags
|= TOPO_NODE_END_OF_STREAM
;
3054 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
&&
3055 session_nodes_is_mask_set(session
, MF_TOPOLOGY_OUTPUT_NODE
, TOPO_NODE_END_OF_STREAM
))
3057 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
3058 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
3059 session_stop(session
);
3063 static HRESULT WINAPI
session_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
3065 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
3066 IMFMediaEventGenerator
*event_source
;
3067 IMFMediaEvent
*event
= NULL
;
3068 MediaEventType event_type
;
3069 IUnknown
*object
= NULL
;
3070 IMFMediaSource
*source
;
3071 IMFMediaStream
*stream
;
3075 if (FAILED(hr
= IMFAsyncResult_GetState(result
, (IUnknown
**)&event_source
)))
3078 if (FAILED(hr
= IMFMediaEventGenerator_EndGetEvent(event_source
, result
, &event
)))
3080 WARN("Failed to get event from %p, hr %#x.\n", event_source
, hr
);
3084 if (FAILED(hr
= IMFMediaEvent_GetType(event
, &event_type
)))
3086 WARN("Failed to get event type, hr %#x.\n", hr
);
3090 value
.vt
= VT_EMPTY
;
3091 if (FAILED(hr
= IMFMediaEvent_GetValue(event
, &value
)))
3093 WARN("Failed to get event value, hr %#x.\n", hr
);
3099 case MESourceStarted
:
3100 case MESourcePaused
:
3101 case MESourceStopped
:
3102 case MEStreamStarted
:
3103 case MEStreamPaused
:
3104 case MEStreamStopped
:
3106 EnterCriticalSection(&session
->cs
);
3107 session_set_source_object_state(session
, (IUnknown
*)event_source
, event_type
);
3108 LeaveCriticalSection(&session
->cs
);
3112 case MEBufferingStarted
:
3113 case MEBufferingStopped
:
3115 EnterCriticalSection(&session
->cs
);
3116 if (session_get_media_source(session
, (IMFMediaSource
*)event_source
))
3118 if (event_type
== MEBufferingStarted
)
3119 IMFPresentationClock_Pause(session
->clock
);
3121 IMFPresentationClock_Start(session
->clock
, PRESENTATION_CURRENT_POSITION
);
3123 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3125 LeaveCriticalSection(&session
->cs
);
3128 case MEReconnectStart
:
3129 case MEReconnectEnd
:
3131 EnterCriticalSection(&session
->cs
);
3132 if (session_get_media_source(session
, (IMFMediaSource
*)event_source
))
3133 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3134 LeaveCriticalSection(&session
->cs
);
3137 case MEExtendedType
:
3138 case MERendererEvent
:
3139 case MEStreamSinkFormatChanged
:
3141 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3145 stream
= (IMFMediaStream
*)value
.punkVal
;
3147 if (value
.vt
!= VT_UNKNOWN
|| !stream
)
3149 WARN("Unexpected event value.\n");
3153 if (FAILED(hr
= IMFMediaStream_GetMediaSource(stream
, &source
)))
3156 EnterCriticalSection(&session
->cs
);
3157 if (SUCCEEDED(hr
= session_add_media_stream(session
, source
, stream
)))
3158 hr
= IMFMediaStream_BeginGetEvent(stream
, &session
->events_callback
, (IUnknown
*)stream
);
3159 LeaveCriticalSection(&session
->cs
);
3161 IMFMediaSource_Release(source
);
3164 case MEStreamSinkStarted
:
3165 case MEStreamSinkPaused
:
3166 case MEStreamSinkStopped
:
3167 case MEStreamSinkPrerolled
:
3169 EnterCriticalSection(&session
->cs
);
3170 session_set_sink_stream_state(session
, (IMFStreamSink
*)event_source
, event_type
);
3171 LeaveCriticalSection(&session
->cs
);
3174 case MEStreamSinkMarker
:
3176 EnterCriticalSection(&session
->cs
);
3177 session_sink_stream_marker(session
, (IMFStreamSink
*)event_source
);
3178 LeaveCriticalSection(&session
->cs
);
3181 case MEStreamSinkRequestSample
:
3183 EnterCriticalSection(&session
->cs
);
3184 session_request_sample(session
, (IMFStreamSink
*)event_source
);
3185 LeaveCriticalSection(&session
->cs
);
3190 EnterCriticalSection(&session
->cs
);
3191 session_deliver_sample(session
, (IMFMediaStream
*)event_source
, &value
);
3192 LeaveCriticalSection(&session
->cs
);
3197 EnterCriticalSection(&session
->cs
);
3198 session_handle_end_of_stream(session
, (IMFMediaStream
*)event_source
);
3199 LeaveCriticalSection(&session
->cs
);
3203 case MEEndOfPresentation
:
3205 EnterCriticalSection(&session
->cs
);
3206 session_handle_end_of_presentation(session
, (IMFMediaSource
*)event_source
);
3207 LeaveCriticalSection(&session
->cs
);
3210 case MEAudioSessionGroupingParamChanged
:
3211 case MEAudioSessionIconChanged
:
3212 case MEAudioSessionNameChanged
:
3213 case MEAudioSessionVolumeChanged
:
3215 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3218 case MEAudioSessionDeviceRemoved
:
3219 case MEAudioSessionDisconnected
:
3220 case MEAudioSessionExclusiveModeOverride
:
3221 case MEAudioSessionFormatChanged
:
3222 case MEAudioSessionServerShutdown
:
3224 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3226 case MESinkInvalidated
:
3228 EnterCriticalSection(&session
->cs
);
3229 session_sink_invalidated(session
, event_type
== MESinkInvalidated
? event
: NULL
,
3230 (IMFStreamSink
*)event_source
);
3231 LeaveCriticalSection(&session
->cs
);
3234 case MEQualityNotify
:
3236 if (session
->quality_manager
)
3238 if (FAILED(IMFMediaEventGenerator_QueryInterface(event_source
, &IID_IMFStreamSink
, (void **)&object
)))
3239 IMFMediaEventGenerator_QueryInterface(event_source
, &IID_IMFTransform
, (void **)&object
);
3243 IMFQualityManager_NotifyQualityEvent(session
->quality_manager
, object
, event
);
3244 IUnknown_Release(object
);
3253 PropVariantClear(&value
);
3257 IMFMediaEvent_Release(event
);
3259 if (FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(event_source
, iface
, (IUnknown
*)event_source
)))
3260 WARN("Failed to re-subscribe, hr %#x.\n", hr
);
3262 IMFMediaEventGenerator_Release(event_source
);
3267 static const IMFAsyncCallbackVtbl session_events_callback_vtbl
=
3269 session_events_callback_QueryInterface
,
3270 session_events_callback_AddRef
,
3271 session_events_callback_Release
,
3272 session_events_callback_GetParameters
,
3273 session_events_callback_Invoke
,
3276 static HRESULT WINAPI
session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
3278 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
3279 IsEqualIID(riid
, &IID_IUnknown
))
3282 IMFAsyncCallback_AddRef(iface
);
3286 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3288 return E_NOINTERFACE
;
3291 static ULONG WINAPI
session_sink_finalizer_callback_AddRef(IMFAsyncCallback
*iface
)
3293 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3294 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3297 static ULONG WINAPI
session_sink_finalizer_callback_Release(IMFAsyncCallback
*iface
)
3299 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3300 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3303 static HRESULT WINAPI
session_sink_finalizer_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
3308 static HRESULT WINAPI
session_sink_finalizer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
3310 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3311 IMFFinalizableMediaSink
*fin_sink
= NULL
;
3312 BOOL sinks_finalized
= TRUE
;
3313 struct media_sink
*sink
;
3317 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
3320 EnterCriticalSection(&session
->cs
);
3322 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
3324 if (state
== (IUnknown
*)sink
->sink
)
3326 if (FAILED(hr
= IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFFinalizableMediaSink
, (void **)&fin_sink
)))
3327 WARN("Unexpected, missing IMFFinalizableSink, hr %#x.\n", hr
);
3331 sinks_finalized
&= sink
->finalized
;
3332 if (!sinks_finalized
)
3337 IUnknown_Release(state
);
3341 /* Complete session transition, or close prematurely on error. */
3342 if (SUCCEEDED(hr
= IMFFinalizableMediaSink_EndFinalize(fin_sink
, result
)))
3344 sink
->finalized
= TRUE
;
3345 if (sinks_finalized
)
3346 session_set_closed(session
, hr
);
3348 IMFFinalizableMediaSink_Release(fin_sink
);
3351 LeaveCriticalSection(&session
->cs
);
3356 static const IMFAsyncCallbackVtbl session_sink_finalizer_callback_vtbl
=
3358 session_sink_finalizer_callback_QueryInterface
,
3359 session_sink_finalizer_callback_AddRef
,
3360 session_sink_finalizer_callback_Release
,
3361 session_sink_finalizer_callback_GetParameters
,
3362 session_sink_finalizer_callback_Invoke
,
3365 static HRESULT WINAPI
session_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
3367 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3368 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
3371 static ULONG WINAPI
session_rate_support_AddRef(IMFRateSupport
*iface
)
3373 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3374 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3377 static ULONG WINAPI
session_rate_support_Release(IMFRateSupport
*iface
)
3379 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3380 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3383 static HRESULT
session_presentation_object_get_rate(IUnknown
*object
, MFRATE_DIRECTION direction
,
3384 BOOL thin
, BOOL fastest
, float *result
)
3386 IMFRateSupport
*rate_support
;
3390 /* For objects that don't support rate control, it's assumed that only forward direction is allowed, at 1.0f. */
3392 if (FAILED(hr
= MFGetService(object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
, (void **)&rate_support
)))
3394 if (direction
== MFRATE_FORWARD
)
3400 return MF_E_REVERSE_UNSUPPORTED
;
3406 if (SUCCEEDED(hr
= IMFRateSupport_GetFastestRate(rate_support
, direction
, thin
, &rate
)))
3407 *result
= min(fabsf(rate
), *result
);
3411 if (SUCCEEDED(hr
= IMFRateSupport_GetSlowestRate(rate_support
, direction
, thin
, &rate
)))
3412 *result
= max(fabsf(rate
), *result
);
3415 IMFRateSupport_Release(rate_support
);
3420 static HRESULT
session_get_presentation_rate(struct media_session
*session
, MFRATE_DIRECTION direction
,
3421 BOOL thin
, BOOL fastest
, float *result
)
3423 struct media_source
*source
;
3424 struct media_sink
*sink
;
3425 HRESULT hr
= E_POINTER
;
3428 rate
= fastest
? FLT_MAX
: 0.0f
;
3430 EnterCriticalSection(&session
->cs
);
3432 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
3434 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3436 if (FAILED(hr
= session_presentation_object_get_rate((IUnknown
*)source
->source
, direction
, thin
, fastest
, &rate
)))
3442 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
3444 if (FAILED(hr
= session_presentation_object_get_rate((IUnknown
*)sink
->sink
, direction
, thin
, fastest
, &rate
)))
3450 LeaveCriticalSection(&session
->cs
);
3453 *result
= direction
== MFRATE_FORWARD
? rate
: -rate
;
3458 static HRESULT WINAPI
session_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
3459 BOOL thin
, float *rate
)
3461 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3463 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
3465 return session_get_presentation_rate(session
, direction
, thin
, FALSE
, rate
);
3468 static HRESULT WINAPI
session_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
3469 BOOL thin
, float *rate
)
3471 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3473 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
3475 return session_get_presentation_rate(session
, direction
, thin
, TRUE
, rate
);
3478 static HRESULT WINAPI
session_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
3479 float *nearest_supported_rate
)
3481 FIXME("%p, %d, %f, %p.\n", iface
, thin
, rate
, nearest_supported_rate
);
3486 static const IMFRateSupportVtbl session_rate_support_vtbl
=
3488 session_rate_support_QueryInterface
,
3489 session_rate_support_AddRef
,
3490 session_rate_support_Release
,
3491 session_rate_support_GetSlowestRate
,
3492 session_rate_support_GetFastestRate
,
3493 session_rate_support_IsRateSupported
,
3496 static HRESULT WINAPI
session_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **obj
)
3498 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3499 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
3502 static ULONG WINAPI
session_rate_control_AddRef(IMFRateControl
*iface
)
3504 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3505 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3508 static ULONG WINAPI
session_rate_control_Release(IMFRateControl
*iface
)
3510 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3511 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3514 static HRESULT WINAPI
session_rate_control_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
3516 FIXME("%p, %d, %f.\n", iface
, thin
, rate
);
3521 static HRESULT WINAPI
session_rate_control_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
3523 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3525 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
3527 return IMFRateControl_GetRate(session
->clock_rate_control
, thin
, rate
);
3530 static const IMFRateControlVtbl session_rate_control_vtbl
=
3532 session_rate_control_QueryInterface
,
3533 session_rate_control_AddRef
,
3534 session_rate_control_Release
,
3535 session_rate_control_SetRate
,
3536 session_rate_control_GetRate
,
3539 static HRESULT WINAPI
node_attribute_editor_QueryInterface(IMFTopologyNodeAttributeEditor
*iface
,
3540 REFIID riid
, void **obj
)
3542 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
3544 if (IsEqualIID(riid
, &IID_IMFTopologyNodeAttributeEditor
) ||
3545 IsEqualIID(riid
, &IID_IUnknown
))
3548 IMFTopologyNodeAttributeEditor_AddRef(iface
);
3552 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
3554 return E_NOINTERFACE
;
3557 static ULONG WINAPI
node_attribute_editor_AddRef(IMFTopologyNodeAttributeEditor
*iface
)
3559 struct media_session
*session
= impl_session_from_IMFTopologyNodeAttributeEditor(iface
);
3560 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3563 static ULONG WINAPI
node_attribute_editor_Release(IMFTopologyNodeAttributeEditor
*iface
)
3565 struct media_session
*session
= impl_session_from_IMFTopologyNodeAttributeEditor(iface
);
3566 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3569 static HRESULT WINAPI
node_attribute_editor_UpdateNodeAttributes(IMFTopologyNodeAttributeEditor
*iface
,
3570 TOPOID id
, DWORD count
, MFTOPONODE_ATTRIBUTE_UPDATE
*updates
)
3572 FIXME("%p, %s, %u, %p.\n", iface
, wine_dbgstr_longlong(id
), count
, updates
);
3577 static const IMFTopologyNodeAttributeEditorVtbl node_attribute_editor_vtbl
=
3579 node_attribute_editor_QueryInterface
,
3580 node_attribute_editor_AddRef
,
3581 node_attribute_editor_Release
,
3582 node_attribute_editor_UpdateNodeAttributes
,
3585 /***********************************************************************
3586 * MFCreateMediaSession (mf.@)
3588 HRESULT WINAPI
MFCreateMediaSession(IMFAttributes
*config
, IMFMediaSession
**session
)
3590 BOOL without_quality_manager
= FALSE
;
3591 struct media_session
*object
;
3594 TRACE("%p, %p.\n", config
, session
);
3596 object
= heap_alloc_zero(sizeof(*object
));
3598 return E_OUTOFMEMORY
;
3600 object
->IMFMediaSession_iface
.lpVtbl
= &mfmediasessionvtbl
;
3601 object
->IMFGetService_iface
.lpVtbl
= &session_get_service_vtbl
;
3602 object
->IMFRateSupport_iface
.lpVtbl
= &session_rate_support_vtbl
;
3603 object
->IMFRateControl_iface
.lpVtbl
= &session_rate_control_vtbl
;
3604 object
->IMFTopologyNodeAttributeEditor_iface
.lpVtbl
= &node_attribute_editor_vtbl
;
3605 object
->commands_callback
.lpVtbl
= &session_commands_callback_vtbl
;
3606 object
->events_callback
.lpVtbl
= &session_events_callback_vtbl
;
3607 object
->sink_finalizer_callback
.lpVtbl
= &session_sink_finalizer_callback_vtbl
;
3608 object
->refcount
= 1;
3609 list_init(&object
->topologies
);
3610 list_init(&object
->commands
);
3611 list_init(&object
->presentation
.sources
);
3612 list_init(&object
->presentation
.sinks
);
3613 list_init(&object
->presentation
.nodes
);
3614 InitializeCriticalSection(&object
->cs
);
3616 if (FAILED(hr
= MFCreateTopology(&object
->presentation
.current_topology
)))
3619 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
3622 if (FAILED(hr
= MFCreatePresentationClock(&object
->clock
)))
3625 if (FAILED(hr
= MFCreateSystemTimeSource(&object
->system_time_source
)))
3628 if (FAILED(hr
= IMFPresentationClock_QueryInterface(object
->clock
, &IID_IMFRateControl
,
3629 (void **)&object
->clock_rate_control
)))
3638 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_TOPOLOADER
, &clsid
)))
3640 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFTopoLoader
,
3641 (void **)&object
->topo_loader
)))
3643 WARN("Failed to create custom topology loader, hr %#x.\n", hr
);
3647 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_QUALITY_MANAGER
, &clsid
)))
3649 if (!(without_quality_manager
= IsEqualGUID(&clsid
, &GUID_NULL
)))
3651 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFQualityManager
,
3652 (void **)&object
->quality_manager
)))
3654 WARN("Failed to create custom quality manager, hr %#x.\n", hr
);
3660 if (!object
->topo_loader
&& FAILED(hr
= MFCreateTopoLoader(&object
->topo_loader
)))
3663 if (!object
->quality_manager
&& !without_quality_manager
&&
3664 FAILED(hr
= MFCreateStandardQualityManager(&object
->quality_manager
)))
3669 if (object
->quality_manager
&& FAILED(hr
= IMFQualityManager_NotifyPresentationClock(object
->quality_manager
,
3675 *session
= &object
->IMFMediaSession_iface
;
3680 IMFMediaSession_Release(&object
->IMFMediaSession_iface
);
3684 static HRESULT WINAPI
standard_quality_manager_QueryInterface(IMFQualityManager
*iface
, REFIID riid
, void **out
)
3686 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
3688 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
3690 if (IsEqualIID(riid
, &IID_IMFQualityManager
) ||
3691 IsEqualIID(riid
, &IID_IUnknown
))
3695 else if (IsEqualIID(riid
, &IID_IMFClockStateSink
))
3697 *out
= &manager
->IMFClockStateSink_iface
;
3701 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3703 return E_NOINTERFACE
;
3706 IUnknown_AddRef((IUnknown
*)*out
);
3710 static ULONG WINAPI
standard_quality_manager_AddRef(IMFQualityManager
*iface
)
3712 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
3713 ULONG refcount
= InterlockedIncrement(&manager
->refcount
);
3715 TRACE("%p, refcount %u.\n", iface
, refcount
);
3720 static ULONG WINAPI
standard_quality_manager_Release(IMFQualityManager
*iface
)
3722 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
3723 ULONG refcount
= InterlockedDecrement(&manager
->refcount
);
3725 TRACE("%p, refcount %u.\n", iface
, refcount
);
3730 IMFPresentationClock_Release(manager
->clock
);
3731 if (manager
->topology
)
3732 IMFTopology_Release(manager
->topology
);
3733 DeleteCriticalSection(&manager
->cs
);
3740 static void standard_quality_manager_set_topology(struct quality_manager
*manager
, IMFTopology
*topology
)
3742 if (manager
->topology
)
3743 IMFTopology_Release(manager
->topology
);
3744 manager
->topology
= topology
;
3745 if (manager
->topology
)
3746 IMFTopology_AddRef(manager
->topology
);
3749 static HRESULT WINAPI
standard_quality_manager_NotifyTopology(IMFQualityManager
*iface
, IMFTopology
*topology
)
3751 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
3754 TRACE("%p, %p.\n", iface
, topology
);
3756 EnterCriticalSection(&manager
->cs
);
3757 if (manager
->state
== QUALITY_MANAGER_SHUT_DOWN
)
3761 standard_quality_manager_set_topology(manager
, topology
);
3763 LeaveCriticalSection(&manager
->cs
);
3768 static void standard_quality_manager_release_clock(struct quality_manager
*manager
)
3772 IMFPresentationClock_RemoveClockStateSink(manager
->clock
, &manager
->IMFClockStateSink_iface
);
3773 IMFPresentationClock_Release(manager
->clock
);
3775 manager
->clock
= NULL
;
3778 static HRESULT WINAPI
standard_quality_manager_NotifyPresentationClock(IMFQualityManager
*iface
,
3779 IMFPresentationClock
*clock
)
3781 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
3784 TRACE("%p, %p.\n", iface
, clock
);
3786 EnterCriticalSection(&manager
->cs
);
3787 if (manager
->state
== QUALITY_MANAGER_SHUT_DOWN
)
3793 standard_quality_manager_release_clock(manager
);
3794 manager
->clock
= clock
;
3795 IMFPresentationClock_AddRef(manager
->clock
);
3796 if (FAILED(IMFPresentationClock_AddClockStateSink(manager
->clock
, &manager
->IMFClockStateSink_iface
)))
3797 WARN("Failed to set state sink.\n");
3799 LeaveCriticalSection(&manager
->cs
);
3804 static HRESULT WINAPI
standard_quality_manager_NotifyProcessInput(IMFQualityManager
*iface
, IMFTopologyNode
*node
,
3805 LONG input_index
, IMFSample
*sample
)
3807 TRACE("%p, %p, %d, %p stub.\n", iface
, node
, input_index
, sample
);
3812 static HRESULT WINAPI
standard_quality_manager_NotifyProcessOutput(IMFQualityManager
*iface
, IMFTopologyNode
*node
,
3813 LONG output_index
, IMFSample
*sample
)
3815 TRACE("%p, %p, %d, %p stub.\n", iface
, node
, output_index
, sample
);
3820 static HRESULT WINAPI
standard_quality_manager_NotifyQualityEvent(IMFQualityManager
*iface
, IUnknown
*object
,
3821 IMFMediaEvent
*event
)
3823 FIXME("%p, %p, %p stub.\n", iface
, object
, event
);
3828 static HRESULT WINAPI
standard_quality_manager_Shutdown(IMFQualityManager
*iface
)
3830 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
3832 TRACE("%p.\n", iface
);
3834 EnterCriticalSection(&manager
->cs
);
3835 if (manager
->state
!= QUALITY_MANAGER_SHUT_DOWN
)
3837 standard_quality_manager_release_clock(manager
);
3838 standard_quality_manager_set_topology(manager
, NULL
);
3839 manager
->state
= QUALITY_MANAGER_SHUT_DOWN
;
3841 LeaveCriticalSection(&manager
->cs
);
3846 static const IMFQualityManagerVtbl standard_quality_manager_vtbl
=
3848 standard_quality_manager_QueryInterface
,
3849 standard_quality_manager_AddRef
,
3850 standard_quality_manager_Release
,
3851 standard_quality_manager_NotifyTopology
,
3852 standard_quality_manager_NotifyPresentationClock
,
3853 standard_quality_manager_NotifyProcessInput
,
3854 standard_quality_manager_NotifyProcessOutput
,
3855 standard_quality_manager_NotifyQualityEvent
,
3856 standard_quality_manager_Shutdown
,
3859 static HRESULT WINAPI
standard_quality_manager_sink_QueryInterface(IMFClockStateSink
*iface
,
3860 REFIID riid
, void **obj
)
3862 struct quality_manager
*manager
= impl_from_qm_IMFClockStateSink(iface
);
3863 return IMFQualityManager_QueryInterface(&manager
->IMFQualityManager_iface
, riid
, obj
);
3866 static ULONG WINAPI
standard_quality_manager_sink_AddRef(IMFClockStateSink
*iface
)
3868 struct quality_manager
*manager
= impl_from_qm_IMFClockStateSink(iface
);
3869 return IMFQualityManager_AddRef(&manager
->IMFQualityManager_iface
);
3872 static ULONG WINAPI
standard_quality_manager_sink_Release(IMFClockStateSink
*iface
)
3874 struct quality_manager
*manager
= impl_from_qm_IMFClockStateSink(iface
);
3875 return IMFQualityManager_Release(&manager
->IMFQualityManager_iface
);
3878 static HRESULT WINAPI
standard_quality_manager_sink_OnClockStart(IMFClockStateSink
*iface
,
3879 MFTIME systime
, LONGLONG offset
)
3884 static HRESULT WINAPI
standard_quality_manager_sink_OnClockStop(IMFClockStateSink
*iface
,
3890 static HRESULT WINAPI
standard_quality_manager_sink_OnClockPause(IMFClockStateSink
*iface
,
3896 static HRESULT WINAPI
standard_quality_manager_sink_OnClockRestart(IMFClockStateSink
*iface
,
3902 static HRESULT WINAPI
standard_quality_manager_sink_OnClockSetRate(IMFClockStateSink
*iface
,
3903 MFTIME systime
, float rate
)
3908 static const IMFClockStateSinkVtbl standard_quality_manager_sink_vtbl
=
3910 standard_quality_manager_sink_QueryInterface
,
3911 standard_quality_manager_sink_AddRef
,
3912 standard_quality_manager_sink_Release
,
3913 standard_quality_manager_sink_OnClockStart
,
3914 standard_quality_manager_sink_OnClockStop
,
3915 standard_quality_manager_sink_OnClockPause
,
3916 standard_quality_manager_sink_OnClockRestart
,
3917 standard_quality_manager_sink_OnClockSetRate
,
3920 HRESULT WINAPI
MFCreateStandardQualityManager(IMFQualityManager
**manager
)
3922 struct quality_manager
*object
;
3924 TRACE("%p.\n", manager
);
3926 object
= heap_alloc_zero(sizeof(*object
));
3928 return E_OUTOFMEMORY
;
3930 object
->IMFQualityManager_iface
.lpVtbl
= &standard_quality_manager_vtbl
;
3931 object
->IMFClockStateSink_iface
.lpVtbl
= &standard_quality_manager_sink_vtbl
;
3932 object
->refcount
= 1;
3933 InitializeCriticalSection(&object
->cs
);
3935 *manager
= &object
->IMFQualityManager_iface
;