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
28 #include "wine/debug.h"
29 #include "wine/heap.h"
30 #include "wine/list.h"
32 #include "mf_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
38 SESSION_CMD_CLEAR_TOPOLOGIES
,
40 SESSION_CMD_SET_TOPOLOGY
,
44 SESSION_CMD_END
, /* Internal use only. */
49 IUnknown IUnknown_iface
;
51 enum session_command command
;
57 IMFTopology
*topology
;
62 PROPVARIANT start_position
;
68 struct queued_topology
71 IMFTopology
*topology
;
77 SESSION_STATE_STOPPED
= 0,
78 SESSION_STATE_STARTING_SOURCES
,
79 SESSION_STATE_PREROLLING_SINKS
,
80 SESSION_STATE_STARTING_SINKS
,
81 SESSION_STATE_STARTED
,
82 SESSION_STATE_PAUSING_SINKS
,
83 SESSION_STATE_PAUSING_SOURCES
,
85 SESSION_STATE_STOPPING_SINKS
,
86 SESSION_STATE_STOPPING_SOURCES
,
87 SESSION_STATE_FINALIZING_SINKS
,
89 SESSION_STATE_SHUT_DOWN
,
94 OBJ_STATE_STOPPED
= 0,
101 enum media_source_flags
103 SOURCE_FLAG_END_OF_PRESENTATION
= 0x1,
109 IMFMediaSource
*source
;
110 IMFPresentationDescriptor
*pd
;
111 enum object_state state
;
119 IMFMediaSinkPreroll
*preroll
;
120 IMFMediaEventGenerator
*event_generator
;
130 struct transform_stream
133 unsigned int requests
;
138 TOPO_NODE_END_OF_STREAM
= 0x1,
144 MF_TOPOLOGY_TYPE type
;
146 IMFTopologyNode
*node
;
147 enum object_state state
;
151 IMFMediaStream
*source_stream
;
152 IMFStreamSink
*sink_stream
;
153 IMFTransform
*transform
;
161 IMFMediaSource
*source
;
162 unsigned int stream_id
;
166 unsigned int requests
;
170 struct transform_stream
*inputs
;
171 unsigned int *input_map
;
172 unsigned int input_count
;
174 struct transform_stream
*outputs
;
175 unsigned int *output_map
;
176 unsigned int output_count
;
181 enum presentation_flags
183 SESSION_FLAG_SOURCES_SUBSCRIBED
= 0x1,
184 SESSION_FLAG_PRESENTATION_CLOCK_SET
= 0x2,
185 SESSION_FLAG_FINALIZE_SINKS
= 0x4,
186 SESSION_FLAG_NEEDS_PREROLL
= 0x8,
187 SESSION_FLAG_END_OF_PRESENTATION
= 0x10,
192 IMFMediaSession IMFMediaSession_iface
;
193 IMFGetService IMFGetService_iface
;
194 IMFRateSupport IMFRateSupport_iface
;
195 IMFRateControl IMFRateControl_iface
;
196 IMFAsyncCallback commands_callback
;
197 IMFAsyncCallback events_callback
;
198 IMFAsyncCallback sink_finalizer_callback
;
200 IMFMediaEventQueue
*event_queue
;
201 IMFPresentationClock
*clock
;
202 IMFPresentationTimeSource
*system_time_source
;
203 IMFRateControl
*clock_rate_control
;
204 IMFTopoLoader
*topo_loader
;
205 IMFQualityManager
*quality_manager
;
208 IMFTopology
*current_topology
;
209 MF_TOPOSTATUS topo_status
;
210 MFTIME clock_stop_time
;
216 /* Latest Start() arguments. */
218 PROPVARIANT start_position
;
220 struct list topologies
;
221 struct list commands
;
222 enum session_state state
;
230 IMFClockStateSink
*state_sink
;
242 enum clock_notification
247 CLOCK_NOTIFY_RESTART
,
248 CLOCK_NOTIFY_SET_RATE
,
251 struct clock_state_change_param
260 struct sink_notification
262 IUnknown IUnknown_iface
;
265 struct clock_state_change_param param
;
266 enum clock_notification notification
;
267 IMFClockStateSink
*sink
;
272 IUnknown IUnknown_iface
;
274 IMFAsyncResult
*result
;
275 IMFAsyncCallback
*callback
;
280 struct presentation_clock
282 IMFPresentationClock IMFPresentationClock_iface
;
283 IMFRateControl IMFRateControl_iface
;
284 IMFTimer IMFTimer_iface
;
285 IMFShutdown IMFShutdown_iface
;
286 IMFAsyncCallback sink_callback
;
287 IMFAsyncCallback timer_callback
;
289 IMFPresentationTimeSource
*time_source
;
290 IMFClockStateSink
*time_source_sink
;
292 LONGLONG start_offset
;
301 struct quality_manager
303 IMFQualityManager IMFQualityManager_iface
;
307 static inline struct media_session
*impl_from_IMFMediaSession(IMFMediaSession
*iface
)
309 return CONTAINING_RECORD(iface
, struct media_session
, IMFMediaSession_iface
);
312 static struct media_session
*impl_from_commands_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
314 return CONTAINING_RECORD(iface
, struct media_session
, commands_callback
);
317 static struct media_session
*impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
319 return CONTAINING_RECORD(iface
, struct media_session
, events_callback
);
322 static struct media_session
*impl_from_sink_finalizer_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
324 return CONTAINING_RECORD(iface
, struct media_session
, sink_finalizer_callback
);
327 static struct media_session
*impl_from_IMFGetService(IMFGetService
*iface
)
329 return CONTAINING_RECORD(iface
, struct media_session
, IMFGetService_iface
);
332 static struct media_session
*impl_session_from_IMFRateSupport(IMFRateSupport
*iface
)
334 return CONTAINING_RECORD(iface
, struct media_session
, IMFRateSupport_iface
);
337 static struct media_session
*impl_session_from_IMFRateControl(IMFRateControl
*iface
)
339 return CONTAINING_RECORD(iface
, struct media_session
, IMFRateControl_iface
);
342 static struct session_op
*impl_op_from_IUnknown(IUnknown
*iface
)
344 return CONTAINING_RECORD(iface
, struct session_op
, IUnknown_iface
);
347 static struct presentation_clock
*impl_from_IMFPresentationClock(IMFPresentationClock
*iface
)
349 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFPresentationClock_iface
);
352 static struct presentation_clock
*impl_from_IMFRateControl(IMFRateControl
*iface
)
354 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFRateControl_iface
);
357 static struct presentation_clock
*impl_from_IMFTimer(IMFTimer
*iface
)
359 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFTimer_iface
);
362 static struct presentation_clock
*impl_from_IMFShutdown(IMFShutdown
*iface
)
364 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFShutdown_iface
);
367 static struct presentation_clock
*impl_from_sink_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
369 return CONTAINING_RECORD(iface
, struct presentation_clock
, sink_callback
);
372 static struct presentation_clock
*impl_from_timer_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
374 return CONTAINING_RECORD(iface
, struct presentation_clock
, timer_callback
);
377 static struct clock_timer
*impl_clock_timer_from_IUnknown(IUnknown
*iface
)
379 return CONTAINING_RECORD(iface
, struct clock_timer
, IUnknown_iface
);
382 static struct sink_notification
*impl_sink_notification_from_IUnknown(IUnknown
*iface
)
384 return CONTAINING_RECORD(iface
, struct sink_notification
, IUnknown_iface
);
387 static struct quality_manager
*impl_from_IMFQualityManager(IMFQualityManager
*iface
)
389 return CONTAINING_RECORD(iface
, struct quality_manager
, IMFQualityManager_iface
);
392 /* IMFLocalMFTRegistration */
393 static HRESULT WINAPI
local_mft_registration_QueryInterface(IMFLocalMFTRegistration
*iface
, REFIID riid
, void **obj
)
395 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
397 if (IsEqualIID(riid
, &IID_IMFLocalMFTRegistration
) ||
398 IsEqualIID(riid
, &IID_IUnknown
))
401 IMFLocalMFTRegistration_AddRef(iface
);
405 WARN("Unexpected %s.\n", debugstr_guid(riid
));
407 return E_NOINTERFACE
;
410 static ULONG WINAPI
local_mft_registration_AddRef(IMFLocalMFTRegistration
*iface
)
415 static ULONG WINAPI
local_mft_registration_Release(IMFLocalMFTRegistration
*iface
)
420 static HRESULT WINAPI
local_mft_registration_RegisterMFTs(IMFLocalMFTRegistration
*iface
, MFT_REGISTRATION_INFO
*info
,
426 TRACE("%p, %p, %u.\n", iface
, info
, count
);
428 for (i
= 0; i
< count
; ++i
)
430 if (FAILED(hr
= MFTRegisterLocalByCLSID(&info
[i
].clsid
, &info
[i
].guidCategory
, info
[i
].pszName
,
431 info
[i
].uiFlags
, info
[i
].cInTypes
, info
[i
].pInTypes
, info
[i
].cOutTypes
, info
[i
].pOutTypes
)))
440 static const IMFLocalMFTRegistrationVtbl local_mft_registration_vtbl
=
442 local_mft_registration_QueryInterface
,
443 local_mft_registration_AddRef
,
444 local_mft_registration_Release
,
445 local_mft_registration_RegisterMFTs
,
448 static IMFLocalMFTRegistration local_mft_registration
= { &local_mft_registration_vtbl
};
450 static HRESULT WINAPI
session_op_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
452 if (IsEqualIID(riid
, &IID_IUnknown
))
455 IUnknown_AddRef(iface
);
460 return E_NOINTERFACE
;
463 static ULONG WINAPI
session_op_AddRef(IUnknown
*iface
)
465 struct session_op
*op
= impl_op_from_IUnknown(iface
);
466 ULONG refcount
= InterlockedIncrement(&op
->refcount
);
468 TRACE("%p, refcount %u.\n", iface
, refcount
);
473 static ULONG WINAPI
session_op_Release(IUnknown
*iface
)
475 struct session_op
*op
= impl_op_from_IUnknown(iface
);
476 ULONG refcount
= InterlockedDecrement(&op
->refcount
);
478 TRACE("%p, refcount %u.\n", iface
, refcount
);
484 case SESSION_CMD_SET_TOPOLOGY
:
485 if (op
->u
.set_topology
.topology
)
486 IMFTopology_Release(op
->u
.set_topology
.topology
);
488 case SESSION_CMD_START
:
489 PropVariantClear(&op
->u
.start
.start_position
);
500 static IUnknownVtbl session_op_vtbl
=
502 session_op_QueryInterface
,
507 static HRESULT
create_session_op(enum session_command command
, struct session_op
**ret
)
509 struct session_op
*op
;
511 if (!(op
= heap_alloc_zero(sizeof(*op
))))
512 return E_OUTOFMEMORY
;
514 op
->IUnknown_iface
.lpVtbl
= &session_op_vtbl
;
516 op
->command
= command
;
523 static HRESULT
session_is_shut_down(struct media_session
*session
)
525 return session
->state
== SESSION_STATE_SHUT_DOWN
? MF_E_SHUTDOWN
: S_OK
;
528 static void session_push_back_command(struct media_session
*session
, enum session_command command
)
530 struct session_op
*op
;
532 if (SUCCEEDED(create_session_op(command
, &op
)))
533 list_add_head(&session
->commands
, &op
->entry
);
536 static HRESULT
session_submit_command(struct media_session
*session
, struct session_op
*op
)
540 EnterCriticalSection(&session
->cs
);
541 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
543 if (list_empty(&session
->commands
))
544 hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &session
->commands_callback
, &op
->IUnknown_iface
);
545 list_add_tail(&session
->commands
, &op
->entry
);
546 IUnknown_AddRef(&op
->IUnknown_iface
);
548 LeaveCriticalSection(&session
->cs
);
553 static HRESULT
session_submit_simple_command(struct media_session
*session
, enum session_command command
)
555 struct session_op
*op
;
558 if (FAILED(hr
= create_session_op(command
, &op
)))
561 hr
= session_submit_command(session
, op
);
562 IUnknown_Release(&op
->IUnknown_iface
);
566 static void session_clear_topologies(struct media_session
*session
)
568 struct queued_topology
*ptr
, *next
;
570 LIST_FOR_EACH_ENTRY_SAFE(ptr
, next
, &session
->topologies
, struct queued_topology
, entry
)
572 list_remove(&ptr
->entry
);
573 IMFTopology_Release(ptr
->topology
);
578 static void session_set_topo_status(struct media_session
*session
, HRESULT status
,
579 MF_TOPOSTATUS topo_status
)
581 IMFMediaEvent
*event
;
584 if (topo_status
== MF_TOPOSTATUS_INVALID
)
587 if (list_empty(&session
->topologies
))
589 FIXME("Unexpectedly empty topology queue.\n");
593 if (topo_status
> session
->presentation
.topo_status
)
595 struct queued_topology
*topology
= LIST_ENTRY(list_head(&session
->topologies
), struct queued_topology
, entry
);
597 param
.vt
= VT_UNKNOWN
;
598 param
.punkVal
= (IUnknown
*)topology
->topology
;
600 if (FAILED(MFCreateMediaEvent(MESessionTopologyStatus
, &GUID_NULL
, status
, ¶m
, &event
)))
603 session
->presentation
.topo_status
= topo_status
;
605 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_TOPOLOGY_STATUS
, topo_status
);
606 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
607 IMFMediaEvent_Release(event
);
611 static HRESULT
session_bind_output_nodes(IMFTopology
*topology
)
613 MF_TOPOLOGY_TYPE node_type
;
614 IMFStreamSink
*stream_sink
;
615 IMFMediaSink
*media_sink
;
616 WORD node_count
= 0, i
;
617 IMFTopologyNode
*node
;
618 IMFActivate
*activate
;
623 hr
= IMFTopology_GetNodeCount(topology
, &node_count
);
625 for (i
= 0; i
< node_count
; ++i
)
627 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
630 if (FAILED(hr
= IMFTopologyNode_GetNodeType(node
, &node_type
)) || node_type
!= MF_TOPOLOGY_OUTPUT_NODE
)
632 IMFTopologyNode_Release(node
);
636 if (SUCCEEDED(hr
= IMFTopologyNode_GetObject(node
, &object
)))
639 if (FAILED(IUnknown_QueryInterface(object
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
641 if (SUCCEEDED(hr
= IUnknown_QueryInterface(object
, &IID_IMFActivate
, (void **)&activate
)))
643 if (SUCCEEDED(hr
= IMFActivate_ActivateObject(activate
, &IID_IMFMediaSink
, (void **)&media_sink
)))
645 if (FAILED(IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_STREAMID
, &stream_id
)))
649 if (FAILED(IMFMediaSink_GetStreamSinkById(media_sink
, stream_id
, &stream_sink
)))
650 hr
= IMFMediaSink_AddStreamSink(media_sink
, stream_id
, NULL
, &stream_sink
);
653 hr
= IMFTopologyNode_SetObject(node
, (IUnknown
*)stream_sink
);
655 IMFMediaSink_Release(media_sink
);
658 IMFActivate_Release(activate
);
663 IMFStreamSink_Release(stream_sink
);
664 IUnknown_Release(object
);
667 IMFTopologyNode_Release(node
);
673 static void session_set_caps(struct media_session
*session
, DWORD caps
)
675 DWORD delta
= session
->caps
^ caps
;
676 IMFMediaEvent
*event
;
678 /* Delta is documented to reflect rate value changes as well, but it's not clear what to compare
679 them to, since session always queries for current object rates. */
683 session
->caps
= caps
;
685 if (FAILED(MFCreateMediaEvent(MESessionCapabilitiesChanged
, &GUID_NULL
, S_OK
, NULL
, &event
)))
688 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_SESSIONCAPS
, caps
);
689 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_SESSIONCAPS_DELTA
, delta
);
691 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
692 IMFMediaEvent_Release(event
);
695 static void transform_release_sample(struct sample
*sample
)
697 list_remove(&sample
->entry
);
699 IMFSample_Release(sample
->sample
);
703 static void transform_stream_drop_samples(struct transform_stream
*stream
)
705 struct sample
*sample
, *sample2
;
707 LIST_FOR_EACH_ENTRY_SAFE(sample
, sample2
, &stream
->samples
, struct sample
, entry
)
708 transform_release_sample(sample
);
711 static void release_topo_node(struct topo_node
*node
)
717 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
718 if (node
->u
.source
.source
)
719 IMFMediaSource_Release(node
->u
.source
.source
);
721 case MF_TOPOLOGY_TRANSFORM_NODE
:
722 for (i
= 0; i
< node
->u
.transform
.input_count
; ++i
)
723 transform_stream_drop_samples(&node
->u
.transform
.inputs
[i
]);
724 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
725 transform_stream_drop_samples(&node
->u
.transform
.outputs
[i
]);
726 heap_free(node
->u
.transform
.inputs
);
727 heap_free(node
->u
.transform
.outputs
);
728 heap_free(node
->u
.transform
.input_map
);
729 heap_free(node
->u
.transform
.output_map
);
735 if (node
->object
.object
)
736 IUnknown_Release(node
->object
.object
);
738 IMFTopologyNode_Release(node
->node
);
742 static void session_clear_presentation(struct media_session
*session
)
744 struct media_source
*source
, *source2
;
745 struct media_sink
*sink
, *sink2
;
746 struct topo_node
*node
, *node2
;
747 struct session_op
*op
, *op2
;
749 IMFTopology_Clear(session
->presentation
.current_topology
);
750 session
->presentation
.topo_status
= MF_TOPOSTATUS_INVALID
;
752 LIST_FOR_EACH_ENTRY_SAFE(source
, source2
, &session
->presentation
.sources
, struct media_source
, entry
)
754 list_remove(&source
->entry
);
756 IMFMediaSource_Release(source
->source
);
758 IMFPresentationDescriptor_Release(source
->pd
);
762 LIST_FOR_EACH_ENTRY_SAFE(node
, node2
, &session
->presentation
.nodes
, struct topo_node
, entry
)
764 list_remove(&node
->entry
);
765 release_topo_node(node
);
768 LIST_FOR_EACH_ENTRY_SAFE(sink
, sink2
, &session
->presentation
.sinks
, struct media_sink
, entry
)
770 list_remove(&sink
->entry
);
773 IMFMediaSink_Release(sink
->sink
);
775 IMFMediaSinkPreroll_Release(sink
->preroll
);
776 if (sink
->event_generator
)
777 IMFMediaEventGenerator_Release(sink
->event_generator
);
781 LIST_FOR_EACH_ENTRY_SAFE(op
, op2
, &session
->commands
, struct session_op
, entry
)
783 list_remove(&op
->entry
);
784 IUnknown_Release(&op
->IUnknown_iface
);
788 static void session_start(struct media_session
*session
, const GUID
*time_format
, const PROPVARIANT
*start_position
)
790 struct media_source
*source
;
793 switch (session
->state
)
795 case SESSION_STATE_STOPPED
:
796 case SESSION_STATE_PAUSED
:
798 session
->presentation
.time_format
= *time_format
;
799 session
->presentation
.start_position
.vt
= VT_EMPTY
;
800 PropVariantCopy(&session
->presentation
.start_position
, start_position
);
802 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
804 if (!(session
->presentation
.flags
& SESSION_FLAG_SOURCES_SUBSCRIBED
))
806 if (FAILED(hr
= IMFMediaSource_BeginGetEvent(source
->source
, &session
->events_callback
,
807 (IUnknown
*)source
->source
)))
809 WARN("Failed to subscribe to source events, hr %#x.\n", hr
);
813 if (FAILED(hr
= IMFMediaSource_Start(source
->source
, source
->pd
, &GUID_NULL
, start_position
)))
814 WARN("Failed to start media source %p, hr %#x.\n", source
->source
, hr
);
817 session
->presentation
.flags
|= SESSION_FLAG_SOURCES_SUBSCRIBED
;
818 session
->state
= SESSION_STATE_STARTING_SOURCES
;
820 case SESSION_STATE_STARTED
:
821 FIXME("Seeking is not implemented.\n");
823 case SESSION_STATE_CLOSED
:
824 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionStarted
, &GUID_NULL
,
825 MF_E_INVALIDREQUEST
, NULL
);
832 static void session_command_complete(struct media_session
*session
)
834 struct session_op
*op
;
837 /* Pop current command, submit next. */
838 if ((e
= list_head(&session
->commands
)))
840 op
= LIST_ENTRY(e
, struct session_op
, entry
);
841 list_remove(&op
->entry
);
842 IUnknown_Release(&op
->IUnknown_iface
);
845 if ((e
= list_head(&session
->commands
)))
847 op
= LIST_ENTRY(e
, struct session_op
, entry
);
848 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &session
->commands_callback
, &op
->IUnknown_iface
);
852 static void session_set_started(struct media_session
*session
)
854 struct media_source
*source
;
855 unsigned int caps
, flags
;
856 IMFMediaEvent
*event
;
858 session
->state
= SESSION_STATE_STARTED
;
860 caps
= session
->caps
| MFSESSIONCAP_PAUSE
;
862 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
864 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source
->source
, &flags
)))
866 if (!(flags
& MFMEDIASOURCE_CAN_PAUSE
))
868 caps
&= ~MFSESSIONCAP_PAUSE
;
874 session_set_caps(session
, caps
);
876 if (SUCCEEDED(MFCreateMediaEvent(MESessionStarted
, &GUID_NULL
, S_OK
, NULL
, &event
)))
878 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_PRESENTATION_TIME_OFFSET
, 0);
879 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
880 IMFMediaEvent_Release(event
);
882 session_command_complete(session
);
885 static void session_set_paused(struct media_session
*session
, HRESULT status
)
887 session
->state
= SESSION_STATE_PAUSED
;
888 if (SUCCEEDED(status
))
889 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
890 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionPaused
, &GUID_NULL
, status
, NULL
);
891 session_command_complete(session
);
894 static void session_set_closed(struct media_session
*session
, HRESULT status
)
896 session
->state
= SESSION_STATE_CLOSED
;
897 if (SUCCEEDED(status
))
898 session_set_caps(session
, session
->caps
& ~(MFSESSIONCAP_START
| MFSESSIONCAP_SEEK
));
899 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionClosed
, &GUID_NULL
, status
, NULL
);
900 session_command_complete(session
);
903 static void session_pause(struct media_session
*session
)
907 switch (session
->state
)
909 case SESSION_STATE_STARTED
:
911 /* Transition in two steps - pause clock, wait for sinks and pause sources. */
912 if (SUCCEEDED(hr
= IMFPresentationClock_Pause(session
->clock
)))
913 session
->state
= SESSION_STATE_PAUSING_SINKS
;
917 hr
= MF_E_INVALIDREQUEST
;
921 session_set_paused(session
, hr
);
924 static void session_set_stopped(struct media_session
*session
, HRESULT status
)
926 MediaEventType event_type
;
927 IMFMediaEvent
*event
;
929 session
->state
= SESSION_STATE_STOPPED
;
930 event_type
= session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
? MESessionEnded
: MESessionStopped
;
932 if (SUCCEEDED(MFCreateMediaEvent(event_type
, &GUID_NULL
, status
, NULL
, &event
)))
934 IMFMediaEvent_SetUINT64(event
, &MF_SESSION_APPROX_EVENT_OCCURRENCE_TIME
, session
->presentation
.clock_stop_time
);
935 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
936 IMFMediaEvent_Release(event
);
938 session_command_complete(session
);
941 static void session_stop(struct media_session
*session
)
943 HRESULT hr
= MF_E_INVALIDREQUEST
;
945 switch (session
->state
)
947 case SESSION_STATE_STARTED
:
948 case SESSION_STATE_PAUSED
:
950 /* Transition in two steps - pause clock, wait for sinks and pause sources. */
951 IMFPresentationClock_GetTime(session
->clock
, &session
->presentation
.clock_stop_time
);
952 if (SUCCEEDED(hr
= IMFPresentationClock_Stop(session
->clock
)))
953 session
->state
= SESSION_STATE_STOPPING_SINKS
;
955 session_set_stopped(session
, hr
);
958 case SESSION_STATE_STOPPED
:
962 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionStopped
, &GUID_NULL
, hr
, NULL
);
963 session_command_complete(session
);
968 static HRESULT
session_finalize_sinks(struct media_session
*session
)
970 IMFFinalizableMediaSink
*fin_sink
;
971 BOOL sinks_finalized
= TRUE
;
972 struct media_sink
*sink
;
975 session
->presentation
.flags
&= ~SESSION_FLAG_FINALIZE_SINKS
;
976 session
->state
= SESSION_STATE_FINALIZING_SINKS
;
978 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
980 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFFinalizableMediaSink
, (void **)&fin_sink
)))
982 hr
= IMFFinalizableMediaSink_BeginFinalize(fin_sink
, &session
->sink_finalizer_callback
,
983 (IUnknown
*)fin_sink
);
984 IMFFinalizableMediaSink_Release(fin_sink
);
987 sinks_finalized
= FALSE
;
990 sink
->finalized
= TRUE
;
994 session_set_closed(session
, hr
);
999 static void session_close(struct media_session
*session
)
1003 switch (session
->state
)
1005 case SESSION_STATE_STOPPED
:
1006 hr
= session_finalize_sinks(session
);
1008 case SESSION_STATE_STARTED
:
1009 case SESSION_STATE_PAUSED
:
1010 session
->presentation
.flags
|= SESSION_FLAG_FINALIZE_SINKS
;
1011 if (SUCCEEDED(hr
= IMFPresentationClock_Stop(session
->clock
)))
1012 session
->state
= SESSION_STATE_STOPPING_SINKS
;
1015 hr
= MF_E_INVALIDREQUEST
;
1020 session_set_closed(session
, hr
);
1023 static struct media_source
*session_get_media_source(struct media_session
*session
, IMFMediaSource
*source
)
1025 struct media_source
*cur
;
1027 LIST_FOR_EACH_ENTRY(cur
, &session
->presentation
.sources
, struct media_source
, entry
)
1029 if (source
== cur
->source
)
1036 static void session_release_media_source(struct media_source
*source
)
1038 IMFMediaSource_Release(source
->source
);
1040 IMFPresentationDescriptor_Release(source
->pd
);
1044 static HRESULT
session_add_media_source(struct media_session
*session
, IMFTopologyNode
*node
, IMFMediaSource
*source
)
1046 struct media_source
*media_source
;
1049 if (session_get_media_source(session
, source
))
1052 if (!(media_source
= heap_alloc_zero(sizeof(*media_source
))))
1053 return E_OUTOFMEMORY
;
1055 media_source
->source
= source
;
1056 IMFMediaSource_AddRef(media_source
->source
);
1058 hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_PRESENTATION_DESCRIPTOR
, &IID_IMFPresentationDescriptor
,
1059 (void **)&media_source
->pd
);
1062 list_add_tail(&session
->presentation
.sources
, &media_source
->entry
);
1064 session_release_media_source(media_source
);
1069 static void session_raise_topology_set(struct media_session
*session
, IMFTopology
*topology
, HRESULT status
)
1073 param
.vt
= topology
? VT_UNKNOWN
: VT_EMPTY
;
1074 param
.punkVal
= (IUnknown
*)topology
;
1076 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionTopologySet
, &GUID_NULL
, status
, ¶m
);
1079 static DWORD
session_get_object_rate_caps(IUnknown
*object
)
1081 IMFRateSupport
*rate_support
;
1085 if (SUCCEEDED(MFGetService(object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
, (void **)&rate_support
)))
1088 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support
, MFRATE_FORWARD
, TRUE
, &rate
)) && rate
!= 0.0f
)
1089 caps
|= MFSESSIONCAP_RATE_FORWARD
;
1092 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support
, MFRATE_REVERSE
, TRUE
, &rate
)) && rate
!= 0.0f
)
1093 caps
|= MFSESSIONCAP_RATE_REVERSE
;
1095 IMFRateSupport_Release(rate_support
);
1101 static HRESULT
session_add_media_sink(struct media_session
*session
, IMFTopologyNode
*node
, IMFMediaSink
*sink
)
1103 struct media_sink
*media_sink
;
1106 LIST_FOR_EACH_ENTRY(media_sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1108 if (sink
== media_sink
->sink
)
1112 if (!(media_sink
= heap_alloc_zero(sizeof(*media_sink
))))
1113 return E_OUTOFMEMORY
;
1115 media_sink
->sink
= sink
;
1116 IMFMediaSink_AddRef(media_sink
->sink
);
1118 IMFMediaSink_QueryInterface(media_sink
->sink
, &IID_IMFMediaEventGenerator
, (void **)&media_sink
->event_generator
);
1120 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink
, &flags
)) && flags
& MEDIASINK_CAN_PREROLL
)
1122 if (SUCCEEDED(IMFMediaSink_QueryInterface(media_sink
->sink
, &IID_IMFMediaSinkPreroll
, (void **)&media_sink
->preroll
)))
1123 session
->presentation
.flags
|= SESSION_FLAG_NEEDS_PREROLL
;
1126 list_add_tail(&session
->presentation
.sinks
, &media_sink
->entry
);
1131 static HRESULT
session_set_transform_stream_info(struct topo_node
*node
)
1133 unsigned int *input_map
= NULL
, *output_map
= NULL
;
1134 unsigned int i
, input_count
, output_count
;
1135 struct transform_stream
*streams
;
1138 hr
= IMFTransform_GetStreamCount(node
->object
.transform
, &input_count
, &output_count
);
1139 if (SUCCEEDED(hr
) && (input_count
> 1 || output_count
> 1))
1141 input_map
= heap_calloc(input_count
, sizeof(*input_map
));
1142 output_map
= heap_calloc(output_count
, sizeof(*output_map
));
1143 if (FAILED(IMFTransform_GetStreamIDs(node
->object
.transform
, input_count
, input_map
,
1144 output_count
, output_map
)))
1146 /* Assume sequential identifiers. */
1147 heap_free(input_map
);
1148 heap_free(output_map
);
1149 input_map
= output_map
= NULL
;
1155 streams
= heap_calloc(input_count
, sizeof(*streams
));
1156 for (i
= 0; i
< input_count
; ++i
)
1157 list_init(&streams
[i
].samples
);
1158 node
->u
.transform
.inputs
= streams
;
1160 streams
= heap_calloc(output_count
, sizeof(*streams
));
1161 for (i
= 0; i
< output_count
; ++i
)
1162 list_init(&streams
[i
].samples
);
1163 node
->u
.transform
.outputs
= streams
;
1165 node
->u
.transform
.input_count
= input_count
;
1166 node
->u
.transform
.output_count
= output_count
;
1167 node
->u
.transform
.input_map
= input_map
;
1168 node
->u
.transform
.output_map
= output_map
;
1174 static HRESULT
session_append_node(struct media_session
*session
, IMFTopologyNode
*node
)
1176 struct topo_node
*topo_node
;
1177 IMFMediaSink
*media_sink
;
1178 IMFStreamDescriptor
*sd
;
1182 if (!(topo_node
= heap_alloc_zero(sizeof(*topo_node
))))
1183 return E_OUTOFMEMORY
;
1185 IMFTopologyNode_GetNodeType(node
, &topo_node
->type
);
1186 IMFTopologyNode_GetTopoNodeID(node
, &topo_node
->node_id
);
1187 topo_node
->node
= node
;
1188 IMFTopologyNode_AddRef(topo_node
->node
);
1190 switch (topo_node
->type
)
1192 case MF_TOPOLOGY_OUTPUT_NODE
:
1193 if (FAILED(hr
= IMFTopologyNode_GetObject(node
, &object
)))
1195 WARN("Node %s does not have associated object.\n", wine_dbgstr_longlong(topo_node
->node_id
));
1198 hr
= IUnknown_QueryInterface(object
, &IID_IMFStreamSink
, (void **)&topo_node
->object
.object
);
1199 IUnknown_Release(object
);
1203 if (FAILED(hr
= IMFStreamSink_GetMediaSink(topo_node
->object
.sink_stream
, &media_sink
)))
1206 hr
= session_add_media_sink(session
, node
, media_sink
);
1207 IMFMediaSink_Release(media_sink
);
1210 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
1211 if (FAILED(IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_SOURCE
, &IID_IMFMediaSource
,
1212 (void **)&topo_node
->u
.source
.source
)))
1214 WARN("Missing MF_TOPONODE_SOURCE, hr %#x.\n", hr
);
1218 if (FAILED(hr
= session_add_media_source(session
, node
, topo_node
->u
.source
.source
)))
1221 if (FAILED(hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_STREAM_DESCRIPTOR
,
1222 &IID_IMFStreamDescriptor
, (void **)&sd
)))
1224 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#x.\n", hr
);
1228 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &topo_node
->u
.source
.stream_id
);
1229 IMFStreamDescriptor_Release(sd
);
1232 case MF_TOPOLOGY_TRANSFORM_NODE
:
1233 if (SUCCEEDED(hr
= IMFTopologyNode_GetObject(node
, &object
)))
1235 hr
= IUnknown_QueryInterface(object
, &IID_IMFTransform
, (void **)&topo_node
->object
.transform
);
1236 IUnknown_Release(object
);
1240 hr
= session_set_transform_stream_info(topo_node
);
1242 WARN("Failed to get IMFTransform for MFT node, hr %#x.\n", hr
);
1245 case MF_TOPOLOGY_TEE_NODE
:
1246 FIXME("Unsupported node type %d.\n", topo_node
->type
);
1254 list_add_tail(&session
->presentation
.nodes
, &topo_node
->entry
);
1256 release_topo_node(topo_node
);
1261 static HRESULT
session_collect_nodes(struct media_session
*session
)
1263 IMFTopology
*topology
= session
->presentation
.current_topology
;
1264 IMFTopologyNode
*node
;
1268 if (!list_empty(&session
->presentation
.nodes
))
1271 if (FAILED(hr
= IMFTopology_GetNodeCount(topology
, &count
)))
1274 for (i
= 0; i
< count
; ++i
)
1276 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
1278 WARN("Failed to get node %u.\n", i
);
1282 hr
= session_append_node(session
, node
);
1283 IMFTopologyNode_Release(node
);
1286 WARN("Failed to add node %u.\n", i
);
1294 static HRESULT
session_set_current_topology(struct media_session
*session
, IMFTopology
*topology
)
1296 struct media_source
*source
;
1297 DWORD caps
, object_flags
;
1298 struct media_sink
*sink
;
1299 struct topo_node
*node
;
1300 IMFMediaEvent
*event
;
1303 if (FAILED(hr
= IMFTopology_CloneFrom(session
->presentation
.current_topology
, topology
)))
1305 WARN("Failed to clone topology, hr %#x.\n", hr
);
1309 session_collect_nodes(session
);
1311 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1313 if (node
->type
== MF_TOPOLOGY_TRANSFORM_NODE
)
1315 if (FAILED(hr
= IMFTransform_ProcessMessage(node
->object
.transform
,
1316 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING
, 0)))
1321 /* FIXME: attributes are all zero for now */
1322 if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime
, &GUID_NULL
, S_OK
, NULL
, &event
)))
1324 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_START_PRESENTATION_TIME
, 0);
1325 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_PRESENTATION_TIME_OFFSET
, 0);
1326 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT
, 0);
1328 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
1329 IMFMediaEvent_Release(event
);
1332 /* Update session caps. */
1333 caps
= MFSESSIONCAP_START
| MFSESSIONCAP_SEEK
| MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
|
1334 MFSESSIONCAP_DOES_NOT_USE_NETWORK
;
1336 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
1342 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source
->source
, &object_flags
)))
1344 if (!(object_flags
& MFMEDIASOURCE_DOES_NOT_USE_NETWORK
))
1345 caps
&= ~MFSESSIONCAP_DOES_NOT_USE_NETWORK
;
1346 if (!(object_flags
& MFMEDIASOURCE_CAN_SEEK
))
1347 caps
&= ~MFSESSIONCAP_SEEK
;
1350 /* Mask unsupported rate caps. */
1352 caps
&= session_get_object_rate_caps((IUnknown
*)source
->source
)
1353 | ~(MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
);
1356 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1362 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink
->sink
, &object_flags
)))
1364 if (!(object_flags
& MEDIASINK_RATELESS
))
1365 caps
&= session_get_object_rate_caps((IUnknown
*)sink
->sink
)
1366 | ~(MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
);
1370 session_set_caps(session
, caps
);
1375 static void session_set_topology(struct media_session
*session
, DWORD flags
, IMFTopology
*topology
)
1377 IMFTopology
*resolved_topology
= NULL
;
1380 /* Resolve unless claimed to be full. */
1381 if (!(flags
& MFSESSION_SETTOPOLOGY_CLEAR_CURRENT
) && topology
)
1383 if (!(flags
& MFSESSION_SETTOPOLOGY_NORESOLUTION
))
1385 hr
= session_bind_output_nodes(topology
);
1388 hr
= IMFTopoLoader_Load(session
->topo_loader
, topology
, &resolved_topology
, NULL
/* FIXME? */);
1392 topology
= resolved_topology
;
1397 if (flags
& MFSESSION_SETTOPOLOGY_CLEAR_CURRENT
)
1399 if ((topology
&& topology
== session
->presentation
.current_topology
) || !topology
)
1401 /* FIXME: stop current topology, queue next one. */
1402 session_clear_presentation(session
);
1409 else if (topology
&& flags
& MFSESSION_SETTOPOLOGY_IMMEDIATE
)
1411 session_clear_topologies(session
);
1412 session_clear_presentation(session
);
1415 session_raise_topology_set(session
, topology
, hr
);
1417 /* With no current topology set it right away, otherwise queue. */
1420 struct queued_topology
*queued_topology
;
1422 if ((queued_topology
= heap_alloc_zero(sizeof(*queued_topology
))))
1424 queued_topology
->topology
= topology
;
1425 IMFTopology_AddRef(queued_topology
->topology
);
1427 list_add_tail(&session
->topologies
, &queued_topology
->entry
);
1430 if (session
->presentation
.topo_status
== MF_TOPOSTATUS_INVALID
)
1432 hr
= session_set_current_topology(session
, topology
);
1433 session_set_topo_status(session
, hr
, MF_TOPOSTATUS_READY
);
1437 if (resolved_topology
)
1438 IMFTopology_Release(resolved_topology
);
1441 static HRESULT WINAPI
mfsession_QueryInterface(IMFMediaSession
*iface
, REFIID riid
, void **out
)
1443 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1445 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1447 if (IsEqualIID(riid
, &IID_IMFMediaSession
) ||
1448 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
1449 IsEqualIID(riid
, &IID_IUnknown
))
1451 *out
= &session
->IMFMediaSession_iface
;
1452 IMFMediaSession_AddRef(iface
);
1455 else if (IsEqualIID(riid
, &IID_IMFGetService
))
1457 *out
= &session
->IMFGetService_iface
;
1458 IMFMediaSession_AddRef(iface
);
1462 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1464 return E_NOINTERFACE
;
1467 static ULONG WINAPI
mfsession_AddRef(IMFMediaSession
*iface
)
1469 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1470 ULONG refcount
= InterlockedIncrement(&session
->refcount
);
1472 TRACE("%p, refcount %u.\n", iface
, refcount
);
1477 static ULONG WINAPI
mfsession_Release(IMFMediaSession
*iface
)
1479 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1480 ULONG refcount
= InterlockedDecrement(&session
->refcount
);
1482 TRACE("%p, refcount %u.\n", iface
, refcount
);
1486 session_clear_topologies(session
);
1487 session_clear_presentation(session
);
1488 if (session
->presentation
.current_topology
)
1489 IMFTopology_Release(session
->presentation
.current_topology
);
1490 if (session
->event_queue
)
1491 IMFMediaEventQueue_Release(session
->event_queue
);
1493 IMFPresentationClock_Release(session
->clock
);
1494 if (session
->system_time_source
)
1495 IMFPresentationTimeSource_Release(session
->system_time_source
);
1496 if (session
->clock_rate_control
)
1497 IMFRateControl_Release(session
->clock_rate_control
);
1498 if (session
->topo_loader
)
1499 IMFTopoLoader_Release(session
->topo_loader
);
1500 if (session
->quality_manager
)
1501 IMFQualityManager_Release(session
->quality_manager
);
1502 DeleteCriticalSection(&session
->cs
);
1509 static HRESULT WINAPI
mfsession_GetEvent(IMFMediaSession
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1511 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1513 TRACE("%p, %#x, %p.\n", iface
, flags
, event
);
1515 return IMFMediaEventQueue_GetEvent(session
->event_queue
, flags
, event
);
1518 static HRESULT WINAPI
mfsession_BeginGetEvent(IMFMediaSession
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
1520 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1522 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1524 return IMFMediaEventQueue_BeginGetEvent(session
->event_queue
, callback
, state
);
1527 static HRESULT WINAPI
mfsession_EndGetEvent(IMFMediaSession
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
1529 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1531 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1533 return IMFMediaEventQueue_EndGetEvent(session
->event_queue
, result
, event
);
1536 static HRESULT WINAPI
mfsession_QueueEvent(IMFMediaSession
*iface
, MediaEventType event_type
, REFGUID ext_type
,
1537 HRESULT hr
, const PROPVARIANT
*value
)
1539 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1541 TRACE("%p, %d, %s, %#x, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1543 return IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, event_type
, ext_type
, hr
, value
);
1546 static HRESULT WINAPI
mfsession_SetTopology(IMFMediaSession
*iface
, DWORD flags
, IMFTopology
*topology
)
1548 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1549 struct session_op
*op
;
1550 WORD node_count
= 0;
1553 TRACE("%p, %#x, %p.\n", iface
, flags
, topology
);
1557 if (FAILED(IMFTopology_GetNodeCount(topology
, &node_count
)) || node_count
== 0)
1558 return E_INVALIDARG
;
1561 if (FAILED(hr
= create_session_op(SESSION_CMD_SET_TOPOLOGY
, &op
)))
1564 op
->u
.set_topology
.flags
= flags
;
1565 op
->u
.set_topology
.topology
= topology
;
1566 if (op
->u
.set_topology
.topology
)
1567 IMFTopology_AddRef(op
->u
.set_topology
.topology
);
1569 hr
= session_submit_command(session
, op
);
1570 IUnknown_Release(&op
->IUnknown_iface
);
1575 static HRESULT WINAPI
mfsession_ClearTopologies(IMFMediaSession
*iface
)
1577 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1579 TRACE("%p.\n", iface
);
1581 return session_submit_simple_command(session
, SESSION_CMD_CLEAR_TOPOLOGIES
);
1584 static HRESULT WINAPI
mfsession_Start(IMFMediaSession
*iface
, const GUID
*format
, const PROPVARIANT
*start_position
)
1586 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1587 struct session_op
*op
;
1590 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(format
), start_position
);
1592 if (!start_position
)
1595 if (FAILED(hr
= create_session_op(SESSION_CMD_START
, &op
)))
1598 op
->u
.start
.time_format
= format
? *format
: GUID_NULL
;
1599 hr
= PropVariantCopy(&op
->u
.start
.start_position
, start_position
);
1602 hr
= session_submit_command(session
, op
);
1604 IUnknown_Release(&op
->IUnknown_iface
);
1609 static HRESULT WINAPI
mfsession_Pause(IMFMediaSession
*iface
)
1611 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1613 TRACE("%p.\n", iface
);
1615 return session_submit_simple_command(session
, SESSION_CMD_PAUSE
);
1618 static HRESULT WINAPI
mfsession_Stop(IMFMediaSession
*iface
)
1620 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1622 TRACE("%p.\n", iface
);
1624 return session_submit_simple_command(session
, SESSION_CMD_STOP
);
1627 static HRESULT WINAPI
mfsession_Close(IMFMediaSession
*iface
)
1629 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1631 TRACE("%p.\n", iface
);
1633 return session_submit_simple_command(session
, SESSION_CMD_CLOSE
);
1636 static HRESULT WINAPI
mfsession_Shutdown(IMFMediaSession
*iface
)
1638 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1641 FIXME("%p.\n", iface
);
1643 EnterCriticalSection(&session
->cs
);
1644 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1646 session
->state
= SESSION_STATE_SHUT_DOWN
;
1647 IMFMediaEventQueue_Shutdown(session
->event_queue
);
1648 if (session
->quality_manager
)
1649 IMFQualityManager_Shutdown(session
->quality_manager
);
1651 LeaveCriticalSection(&session
->cs
);
1656 static HRESULT WINAPI
mfsession_GetClock(IMFMediaSession
*iface
, IMFClock
**clock
)
1658 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1661 TRACE("%p, %p.\n", iface
, clock
);
1663 EnterCriticalSection(&session
->cs
);
1664 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1666 *clock
= (IMFClock
*)session
->clock
;
1667 IMFClock_AddRef(*clock
);
1669 LeaveCriticalSection(&session
->cs
);
1674 static HRESULT WINAPI
mfsession_GetSessionCapabilities(IMFMediaSession
*iface
, DWORD
*caps
)
1676 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1679 TRACE("%p, %p.\n", iface
, caps
);
1684 EnterCriticalSection(&session
->cs
);
1685 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1686 *caps
= session
->caps
;
1687 LeaveCriticalSection(&session
->cs
);
1692 static HRESULT WINAPI
mfsession_GetFullTopology(IMFMediaSession
*iface
, DWORD flags
, TOPOID id
, IMFTopology
**topology
)
1694 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1695 struct queued_topology
*queued
;
1699 TRACE("%p, %#x, %s, %p.\n", iface
, flags
, wine_dbgstr_longlong(id
), topology
);
1703 EnterCriticalSection(&session
->cs
);
1705 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1707 if (flags
& MFSESSION_GETFULLTOPOLOGY_CURRENT
)
1709 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
1710 *topology
= session
->presentation
.current_topology
;
1712 hr
= MF_E_INVALIDREQUEST
;
1716 LIST_FOR_EACH_ENTRY(queued
, &session
->topologies
, struct queued_topology
, entry
)
1718 if (SUCCEEDED(IMFTopology_GetTopologyID(queued
->topology
, &topo_id
)) && topo_id
== id
)
1720 *topology
= queued
->topology
;
1727 IMFTopology_AddRef(*topology
);
1730 LeaveCriticalSection(&session
->cs
);
1735 static const IMFMediaSessionVtbl mfmediasessionvtbl
=
1737 mfsession_QueryInterface
,
1741 mfsession_BeginGetEvent
,
1742 mfsession_EndGetEvent
,
1743 mfsession_QueueEvent
,
1744 mfsession_SetTopology
,
1745 mfsession_ClearTopologies
,
1752 mfsession_GetSessionCapabilities
,
1753 mfsession_GetFullTopology
,
1756 static HRESULT WINAPI
session_get_service_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
1758 struct media_session
*session
= impl_from_IMFGetService(iface
);
1759 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
1762 static ULONG WINAPI
session_get_service_AddRef(IMFGetService
*iface
)
1764 struct media_session
*session
= impl_from_IMFGetService(iface
);
1765 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
1768 static ULONG WINAPI
session_get_service_Release(IMFGetService
*iface
)
1770 struct media_session
*session
= impl_from_IMFGetService(iface
);
1771 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
1774 static HRESULT WINAPI
session_get_service_GetService(IMFGetService
*iface
, REFGUID service
, REFIID riid
, void **obj
)
1776 struct media_session
*session
= impl_from_IMFGetService(iface
);
1778 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
1782 if (IsEqualGUID(service
, &MF_RATE_CONTROL_SERVICE
))
1784 if (IsEqualIID(riid
, &IID_IMFRateSupport
))
1786 *obj
= &session
->IMFRateSupport_iface
;
1788 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
1790 *obj
= &session
->IMFRateControl_iface
;
1793 else if (IsEqualGUID(service
, &MF_LOCAL_MFT_REGISTRATION_SERVICE
))
1795 return IMFLocalMFTRegistration_QueryInterface(&local_mft_registration
, riid
, obj
);
1798 FIXME("Unsupported service %s.\n", debugstr_guid(service
));
1801 IUnknown_AddRef((IUnknown
*)*obj
);
1803 return *obj
? S_OK
: E_NOINTERFACE
;
1806 static const IMFGetServiceVtbl session_get_service_vtbl
=
1808 session_get_service_QueryInterface
,
1809 session_get_service_AddRef
,
1810 session_get_service_Release
,
1811 session_get_service_GetService
,
1814 static HRESULT WINAPI
session_commands_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
1816 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
1817 IsEqualIID(riid
, &IID_IUnknown
))
1820 IMFAsyncCallback_AddRef(iface
);
1824 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1826 return E_NOINTERFACE
;
1829 static ULONG WINAPI
session_commands_callback_AddRef(IMFAsyncCallback
*iface
)
1831 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
1832 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
1835 static ULONG WINAPI
session_commands_callback_Release(IMFAsyncCallback
*iface
)
1837 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
1838 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
1841 static HRESULT WINAPI
session_commands_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
1846 static HRESULT WINAPI
session_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1848 struct session_op
*op
= impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result
));
1849 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
1851 EnterCriticalSection(&session
->cs
);
1853 switch (op
->command
)
1855 case SESSION_CMD_CLEAR_TOPOLOGIES
:
1856 session_clear_topologies(session
);
1857 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionTopologiesCleared
, &GUID_NULL
,
1859 session_command_complete(session
);
1861 case SESSION_CMD_SET_TOPOLOGY
:
1862 session_set_topology(session
, op
->u
.set_topology
.flags
, op
->u
.set_topology
.topology
);
1863 session_command_complete(session
);
1865 case SESSION_CMD_START
:
1866 session_start(session
, &op
->u
.start
.time_format
, &op
->u
.start
.start_position
);
1868 case SESSION_CMD_PAUSE
:
1869 session_pause(session
);
1871 case SESSION_CMD_STOP
:
1872 session_stop(session
);
1874 case SESSION_CMD_CLOSE
:
1875 session_close(session
);
1881 LeaveCriticalSection(&session
->cs
);
1886 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl
=
1888 session_commands_callback_QueryInterface
,
1889 session_commands_callback_AddRef
,
1890 session_commands_callback_Release
,
1891 session_commands_callback_GetParameters
,
1892 session_commands_callback_Invoke
,
1895 static HRESULT WINAPI
session_events_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
1897 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
1898 IsEqualIID(riid
, &IID_IUnknown
))
1901 IMFAsyncCallback_AddRef(iface
);
1905 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1907 return E_NOINTERFACE
;
1910 static ULONG WINAPI
session_events_callback_AddRef(IMFAsyncCallback
*iface
)
1912 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
1913 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
1916 static ULONG WINAPI
session_events_callback_Release(IMFAsyncCallback
*iface
)
1918 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
1919 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
1922 static HRESULT WINAPI
session_events_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
1927 static HRESULT
session_add_media_stream(struct media_session
*session
, IMFMediaSource
*source
, IMFMediaStream
*stream
)
1929 struct topo_node
*node
;
1930 IMFStreamDescriptor
*sd
;
1931 DWORD stream_id
= 0;
1934 if (FAILED(hr
= IMFMediaStream_GetStreamDescriptor(stream
, &sd
)))
1937 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &stream_id
);
1938 IMFStreamDescriptor_Release(sd
);
1942 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1944 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->u
.source
.source
== source
1945 && node
->u
.source
.stream_id
== stream_id
)
1947 if (node
->object
.source_stream
)
1949 WARN("Node already has stream set.\n");
1953 node
->object
.source_stream
= stream
;
1954 IMFMediaStream_AddRef(node
->object
.source_stream
);
1962 static BOOL
session_is_source_nodes_state(struct media_session
*session
, enum object_state state
)
1964 struct media_source
*source
;
1965 struct topo_node
*node
;
1967 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
1969 if (source
->state
!= state
)
1973 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1975 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->state
!= state
)
1982 static BOOL
session_is_output_nodes_state(struct media_session
*session
, enum object_state state
)
1984 struct topo_node
*node
;
1986 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1988 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->state
!= state
)
1995 static enum object_state
session_get_object_state_for_event(MediaEventType event
)
1999 case MESourceStarted
:
2000 case MEStreamStarted
:
2001 case MEStreamSinkStarted
:
2002 return OBJ_STATE_STARTED
;
2003 case MESourcePaused
:
2004 case MEStreamPaused
:
2005 case MEStreamSinkPaused
:
2006 return OBJ_STATE_PAUSED
;
2007 case MESourceStopped
:
2008 case MEStreamStopped
:
2009 case MEStreamSinkStopped
:
2010 return OBJ_STATE_STOPPED
;
2011 case MEStreamSinkPrerolled
:
2012 return OBJ_STATE_PREROLLED
;
2014 return OBJ_STATE_INVALID
;
2018 static void session_set_consumed_clock(IUnknown
*object
, IMFPresentationClock
*clock
)
2020 IMFClockConsumer
*consumer
;
2022 if (SUCCEEDED(IUnknown_QueryInterface(object
, &IID_IMFClockConsumer
, (void **)&consumer
)))
2024 IMFClockConsumer_SetPresentationClock(consumer
, clock
);
2025 IMFClockConsumer_Release(consumer
);
2029 static void session_set_presentation_clock(struct media_session
*session
)
2031 IMFPresentationTimeSource
*time_source
= NULL
;
2032 struct media_source
*source
;
2033 struct media_sink
*sink
;
2034 struct topo_node
*node
;
2037 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2039 if (node
->type
== MF_TOPOLOGY_TRANSFORM_NODE
)
2040 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_NOTIFY_START_OF_STREAM
, 0);
2043 if (!(session
->presentation
.flags
& SESSION_FLAG_PRESENTATION_CLOCK_SET
))
2045 /* Attempt to get time source from the sinks. */
2046 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2048 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFPresentationTimeSource
,
2049 (void **)&time_source
)))
2055 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, time_source
);
2056 IMFPresentationTimeSource_Release(time_source
);
2059 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, session
->system_time_source
);
2062 WARN("Failed to set time source, hr %#x.\n", hr
);
2064 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2066 if (node
->type
!= MF_TOPOLOGY_OUTPUT_NODE
)
2069 if (FAILED(hr
= IMFStreamSink_BeginGetEvent(node
->object
.sink_stream
, &session
->events_callback
,
2070 node
->object
.object
)))
2072 WARN("Failed to subscribe to stream sink events, hr %#x.\n", hr
);
2076 /* Set clock for all topology nodes. */
2077 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2079 session_set_consumed_clock((IUnknown
*)source
->source
, session
->clock
);
2082 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2084 if (sink
->event_generator
&& FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(sink
->event_generator
,
2085 &session
->events_callback
, (IUnknown
*)sink
->event_generator
)))
2087 WARN("Failed to subscribe to sink events, hr %#x.\n", hr
);
2090 if (FAILED(hr
= IMFMediaSink_SetPresentationClock(sink
->sink
, session
->clock
)))
2091 WARN("Failed to set presentation clock for the sink, hr %#x.\n", hr
);
2094 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2096 if (node
->type
!= MF_TOPOLOGY_TRANSFORM_NODE
)
2099 session_set_consumed_clock(node
->object
.object
, session
->clock
);
2102 session
->presentation
.flags
|= SESSION_FLAG_PRESENTATION_CLOCK_SET
;
2106 static HRESULT
session_start_clock(struct media_session
*session
)
2108 LONGLONG start_offset
= 0;
2111 if (IsEqualGUID(&session
->presentation
.time_format
, &GUID_NULL
))
2113 if (session
->presentation
.start_position
.vt
== VT_EMPTY
)
2114 start_offset
= PRESENTATION_CURRENT_POSITION
;
2115 else if (session
->presentation
.start_position
.vt
== VT_I8
)
2116 start_offset
= session
->presentation
.start_position
.hVal
.QuadPart
;
2118 FIXME("Unhandled position type %d.\n", session
->presentation
.start_position
.vt
);
2121 FIXME("Unhandled time format %s.\n", debugstr_guid(&session
->presentation
.time_format
));
2123 if (FAILED(hr
= IMFPresentationClock_Start(session
->clock
, start_offset
)))
2124 WARN("Failed to start session clock, hr %#x.\n", hr
);
2129 static struct topo_node
*session_get_node_object(struct media_session
*session
, IUnknown
*object
,
2130 MF_TOPOLOGY_TYPE node_type
)
2132 struct topo_node
*node
= NULL
;
2134 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2136 if (node
->type
== node_type
&& object
== node
->object
.object
)
2143 static BOOL
session_set_node_object_state(struct media_session
*session
, IUnknown
*object
,
2144 MF_TOPOLOGY_TYPE node_type
, enum object_state state
)
2146 struct topo_node
*node
;
2147 BOOL changed
= FALSE
;
2149 if ((node
= session_get_node_object(session
, object
, node_type
)))
2151 changed
= node
->state
!= state
;
2152 node
->state
= state
;
2158 static void session_set_source_object_state(struct media_session
*session
, IUnknown
*object
,
2159 MediaEventType event_type
)
2161 IMFStreamSink
*stream_sink
;
2162 struct media_source
*src
;
2163 struct media_sink
*sink
;
2164 enum object_state state
;
2165 struct topo_node
*node
;
2166 unsigned int i
, count
;
2167 BOOL changed
= FALSE
;
2170 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2175 case MESourceStarted
:
2176 case MESourcePaused
:
2177 case MESourceStopped
:
2179 LIST_FOR_EACH_ENTRY(src
, &session
->presentation
.sources
, struct media_source
, entry
)
2181 if (object
== (IUnknown
*)src
->source
)
2183 changed
= src
->state
!= state
;
2189 case MEStreamStarted
:
2190 case MEStreamPaused
:
2191 case MEStreamStopped
:
2193 changed
= session_set_node_object_state(session
, object
, MF_TOPOLOGY_SOURCESTREAM_NODE
, state
);
2201 switch (session
->state
)
2203 case SESSION_STATE_STARTING_SOURCES
:
2204 if (!session_is_source_nodes_state(session
, OBJ_STATE_STARTED
))
2207 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_STARTED_SOURCE
);
2209 session_set_presentation_clock(session
);
2211 if (session
->presentation
.flags
& SESSION_FLAG_NEEDS_PREROLL
)
2213 MFTIME preroll_time
= 0;
2215 if (session
->presentation
.start_position
.vt
== VT_I8
)
2216 preroll_time
= session
->presentation
.start_position
.hVal
.QuadPart
;
2218 /* Mark stream sinks without prerolling support as PREROLLED to keep state test logic generic. */
2219 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2223 /* FIXME: abort and enter error state on failure. */
2224 if (FAILED(hr
= IMFMediaSinkPreroll_NotifyPreroll(sink
->preroll
, preroll_time
)))
2225 WARN("Preroll notification failed, hr %#x.\n", hr
);
2229 if (SUCCEEDED(IMFMediaSink_GetStreamSinkCount(sink
->sink
, &count
)))
2231 for (i
= 0; i
< count
; ++i
)
2233 if (SUCCEEDED(IMFMediaSink_GetStreamSinkByIndex(sink
->sink
, i
, &stream_sink
)))
2235 session_set_node_object_state(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
,
2236 OBJ_STATE_PREROLLED
);
2237 IMFStreamSink_Release(stream_sink
);
2243 session
->state
= SESSION_STATE_PREROLLING_SINKS
;
2245 else if (SUCCEEDED(session_start_clock(session
)))
2246 session
->state
= SESSION_STATE_STARTING_SINKS
;
2249 case SESSION_STATE_PAUSING_SOURCES
:
2250 if (!session_is_source_nodes_state(session
, OBJ_STATE_PAUSED
))
2253 session_set_paused(session
, S_OK
);
2255 case SESSION_STATE_STOPPING_SOURCES
:
2256 if (!session_is_source_nodes_state(session
, OBJ_STATE_STOPPED
))
2259 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2263 case MF_TOPOLOGY_OUTPUT_NODE
:
2264 IMFStreamSink_Flush(node
->object
.sink_stream
);
2266 case MF_TOPOLOGY_TRANSFORM_NODE
:
2267 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_COMMAND_FLUSH
, 0);
2274 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
2276 if (session
->presentation
.flags
& SESSION_FLAG_FINALIZE_SINKS
)
2277 session_finalize_sinks(session
);
2279 session_set_stopped(session
, S_OK
);
2287 static void session_set_sink_stream_state(struct media_session
*session
, IMFStreamSink
*stream
,
2288 MediaEventType event_type
)
2290 struct media_source
*source
;
2291 enum object_state state
;
2295 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2298 if (!(changed
= session_set_node_object_state(session
, (IUnknown
*)stream
, MF_TOPOLOGY_OUTPUT_NODE
, state
)))
2301 switch (session
->state
)
2303 case SESSION_STATE_PREROLLING_SINKS
:
2304 if (!session_is_output_nodes_state(session
, OBJ_STATE_PREROLLED
))
2307 if (SUCCEEDED(session_start_clock(session
)))
2308 session
->state
= SESSION_STATE_STARTING_SINKS
;
2310 case SESSION_STATE_STARTING_SINKS
:
2311 if (!session_is_output_nodes_state(session
, OBJ_STATE_STARTED
))
2314 session_set_started(session
);
2316 case SESSION_STATE_PAUSING_SINKS
:
2317 if (!session_is_output_nodes_state(session
, OBJ_STATE_PAUSED
))
2320 session
->state
= SESSION_STATE_PAUSING_SOURCES
;
2322 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2324 if (FAILED(hr
= IMFMediaSource_Pause(source
->source
)))
2329 session_set_paused(session
, hr
);
2332 case SESSION_STATE_STOPPING_SINKS
:
2333 if (!session_is_output_nodes_state(session
, OBJ_STATE_STOPPED
))
2336 session
->state
= SESSION_STATE_STOPPING_SOURCES
;
2338 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2340 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
)
2341 IMFMediaSource_Stop(source
->source
);
2342 else if (FAILED(hr
= IMFMediaSource_Stop(source
->source
)))
2346 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
|| FAILED(hr
))
2347 session_set_stopped(session
, hr
);
2355 static struct topo_node
*session_get_node_by_id(struct media_session
*session
, TOPOID id
)
2357 struct topo_node
*node
;
2359 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2361 if (node
->node_id
== id
)
2368 static DWORD
transform_node_get_stream_id(struct topo_node
*node
, BOOL output
, DWORD index
)
2370 unsigned int *map
= output
? node
->u
.transform
.output_map
: node
->u
.transform
.input_map
;
2371 return map
? map
[index
] : index
;
2374 static struct sample
*transform_create_sample(IMFSample
*sample
)
2376 struct sample
*sample_entry
= heap_alloc_zero(sizeof(*sample_entry
));
2380 sample_entry
->sample
= sample
;
2381 if (sample_entry
->sample
)
2382 IMFSample_AddRef(sample_entry
->sample
);
2385 return sample_entry
;
2388 static HRESULT
transform_node_pull_samples(struct topo_node
*node
)
2390 MFT_OUTPUT_STREAM_INFO stream_info
;
2391 MFT_OUTPUT_DATA_BUFFER
*buffers
;
2392 struct sample
*queued_sample
;
2397 if (!(buffers
= heap_calloc(node
->u
.transform
.output_count
, sizeof(*buffers
))))
2398 return E_OUTOFMEMORY
;
2400 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
2402 buffers
[i
].dwStreamID
= transform_node_get_stream_id(node
, TRUE
, i
);
2403 buffers
[i
].pSample
= NULL
;
2404 buffers
[i
].dwStatus
= 0;
2405 buffers
[i
].pEvents
= NULL
;
2407 memset(&stream_info
, 0, sizeof(stream_info
));
2408 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(node
->object
.transform
, buffers
[i
].dwStreamID
, &stream_info
)))
2411 if (!(stream_info
.dwFlags
& MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
))
2413 IMFMediaBuffer
*buffer
= NULL
;
2415 hr
= MFCreateAlignedMemoryBuffer(stream_info
.cbSize
, stream_info
.cbAlignment
, &buffer
);
2417 hr
= MFCreateSample(&buffers
[i
].pSample
);
2420 hr
= IMFSample_AddBuffer(buffers
[i
].pSample
, buffer
);
2423 IMFMediaBuffer_Release(buffer
);
2431 hr
= IMFTransform_ProcessOutput(node
->object
.transform
, 0, node
->u
.transform
.output_count
, buffers
, &status
);
2433 /* Collect returned samples for all streams. */
2434 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
2436 if (buffers
[i
].pEvents
)
2437 IMFCollection_Release(buffers
[i
].pEvents
);
2439 if (SUCCEEDED(hr
) && !(buffers
[i
].dwStatus
& MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE
))
2441 queued_sample
= transform_create_sample(buffers
[i
].pSample
);
2442 list_add_tail(&node
->u
.transform
.outputs
[i
].samples
, &queued_sample
->entry
);
2445 if (buffers
[i
].pSample
)
2446 IMFSample_Release(buffers
[i
].pSample
);
2454 static void session_deliver_sample_to_node(struct media_session
*session
, IMFTopologyNode
*node
, unsigned int input
,
2457 struct sample
*sample_entry
, *sample_entry2
;
2458 DWORD stream_id
, downstream_input
;
2459 IMFTopologyNode
*downstream_node
;
2460 struct topo_node
*topo_node
;
2461 MF_TOPOLOGY_TYPE node_type
;
2467 IMFTopologyNode_GetNodeType(node
, &node_type
);
2468 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
2470 topo_node
= session_get_node_by_id(session
, node_id
);
2474 case MF_TOPOLOGY_OUTPUT_NODE
:
2477 if (topo_node
->u
.sink
.requests
)
2479 if (FAILED(hr
= IMFStreamSink_ProcessSample(topo_node
->object
.sink_stream
, sample
)))
2480 WARN("Stream sink failed to process sample, hr %#x.\n", hr
);
2481 topo_node
->u
.sink
.requests
--;
2484 else if (FAILED(hr
= IMFStreamSink_PlaceMarker(topo_node
->object
.sink_stream
, MFSTREAMSINK_MARKER_ENDOFSEGMENT
,
2487 WARN("Failed to place sink marker, hr %#x.\n", hr
);
2490 case MF_TOPOLOGY_TRANSFORM_NODE
:
2492 transform_node_pull_samples(topo_node
);
2494 sample_entry
= transform_create_sample(sample
);
2495 list_add_tail(&topo_node
->u
.transform
.inputs
[input
].samples
, &sample_entry
->entry
);
2497 for (i
= 0; i
< topo_node
->u
.transform
.input_count
; ++i
)
2499 stream_id
= transform_node_get_stream_id(topo_node
, FALSE
, i
);
2500 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.inputs
[i
].samples
,
2501 struct sample
, entry
)
2503 if (sample_entry
->sample
)
2505 if ((hr
= IMFTransform_ProcessInput(topo_node
->object
.transform
, stream_id
,
2506 sample_entry
->sample
, 0)) == MF_E_NOTACCEPTING
)
2509 WARN("Failed to process input for stream %u/%u, hr %#x.\n", i
, stream_id
, hr
);
2510 transform_release_sample(sample_entry
);
2514 transform_stream_drop_samples(&topo_node
->u
.transform
.inputs
[i
]);
2522 if (FAILED(hr
= IMFTransform_ProcessMessage(topo_node
->object
.transform
, MFT_MESSAGE_COMMAND_DRAIN
, 0)))
2523 WARN("Drain command failed for transform, hr %#x.\n", hr
);
2526 transform_node_pull_samples(topo_node
);
2528 /* Remaining unprocessed input has been discarded, now queue markers for every output. */
2531 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
2533 if ((sample_entry
= transform_create_sample(NULL
)))
2534 list_add_tail(&topo_node
->u
.transform
.outputs
[i
].samples
, &sample_entry
->entry
);
2538 /* Push down all available output. */
2539 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
2541 if (FAILED(IMFTopologyNode_GetOutput(node
, i
, &downstream_node
, &downstream_input
)))
2543 WARN("Failed to get connected node for output %u.\n", i
);
2547 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.outputs
[i
].samples
,
2548 struct sample
, entry
)
2550 if (!topo_node
->u
.transform
.outputs
[i
].requests
)
2553 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample_entry
->sample
);
2554 topo_node
->u
.transform
.outputs
[i
].requests
--;
2556 transform_release_sample(sample_entry
);
2559 IMFTopologyNode_Release(downstream_node
);
2563 case MF_TOPOLOGY_TEE_NODE
:
2564 FIXME("Unhandled downstream node type %d.\n", node_type
);
2571 static HRESULT
session_request_sample_from_node(struct media_session
*session
, IMFTopologyNode
*node
, DWORD output
)
2573 IMFTopologyNode
*downstream_node
, *upstream_node
;
2574 unsigned int downstream_input
, upstream_output
;
2575 struct topo_node
*topo_node
;
2576 MF_TOPOLOGY_TYPE node_type
;
2577 struct sample
*sample
;
2581 IMFTopologyNode_GetNodeType(node
, &node_type
);
2582 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
2584 topo_node
= session_get_node_by_id(session
, node_id
);
2588 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
2589 if (FAILED(hr
= IMFMediaStream_RequestSample(topo_node
->object
.source_stream
, NULL
)))
2590 WARN("Sample request failed, hr %#x.\n", hr
);
2592 case MF_TOPOLOGY_TRANSFORM_NODE
:
2594 if (list_empty(&topo_node
->u
.transform
.outputs
[output
].samples
))
2596 /* Forward request to upstream node. */
2597 if (SUCCEEDED(hr
= IMFTopologyNode_GetInput(node
, 0 /* FIXME */, &upstream_node
, &upstream_output
)))
2599 if (SUCCEEDED(hr
= session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
2600 topo_node
->u
.transform
.outputs
[output
].requests
++;
2601 IMFTopologyNode_Release(upstream_node
);
2606 if (SUCCEEDED(hr
= IMFTopologyNode_GetOutput(node
, output
, &downstream_node
, &downstream_input
)))
2608 sample
= LIST_ENTRY(list_head(&topo_node
->u
.transform
.outputs
[output
].samples
), struct sample
, entry
);
2609 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample
->sample
);
2610 transform_release_sample(sample
);
2611 IMFTopologyNode_Release(downstream_node
);
2616 case MF_TOPOLOGY_TEE_NODE
:
2617 FIXME("Unhandled upstream node type %d.\n", node_type
);
2625 static void session_request_sample(struct media_session
*session
, IMFStreamSink
*sink_stream
)
2627 struct topo_node
*sink_node
= NULL
, *node
;
2628 IMFTopologyNode
*upstream_node
;
2629 DWORD upstream_output
;
2632 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2634 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink_stream
)
2644 if (FAILED(hr
= IMFTopologyNode_GetInput(sink_node
->node
, 0, &upstream_node
, &upstream_output
)))
2646 WARN("Failed to get upstream node connection, hr %#x.\n", hr
);
2650 if (SUCCEEDED(session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
2651 sink_node
->u
.sink
.requests
++;
2652 IMFTopologyNode_Release(upstream_node
);
2655 static void session_deliver_sample(struct media_session
*session
, IMFMediaStream
*stream
, const PROPVARIANT
*value
)
2657 struct topo_node
*source_node
= NULL
, *node
;
2658 IMFTopologyNode
*downstream_node
;
2659 DWORD downstream_input
;
2662 if (value
&& (value
->vt
!= VT_UNKNOWN
|| !value
->punkVal
))
2664 WARN("Unexpected value type %d.\n", value
->vt
);
2668 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2670 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->object
.source_stream
== stream
)
2681 source_node
->flags
|= TOPO_NODE_END_OF_STREAM
;
2683 if (FAILED(hr
= IMFTopologyNode_GetOutput(source_node
->node
, 0, &downstream_node
, &downstream_input
)))
2685 WARN("Failed to get downstream node connection, hr %#x.\n", hr
);
2689 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, value
? (IMFSample
*)value
->punkVal
: NULL
);
2690 IMFTopologyNode_Release(downstream_node
);
2693 static void session_sink_invalidated(struct media_session
*session
, IMFMediaEvent
*event
, IMFStreamSink
*sink
)
2695 struct topo_node
*node
, *sink_node
= NULL
;
2698 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2700 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink
)
2712 if (FAILED(hr
= MFCreateMediaEvent(MESinkInvalidated
, &GUID_NULL
, S_OK
, NULL
, &event
)))
2713 WARN("Failed to create event, hr %#x.\n", hr
);
2719 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_OUTPUT_NODE
, sink_node
->node_id
);
2720 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
2722 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
2725 static BOOL
session_nodes_is_mask_set(struct media_session
*session
, MF_TOPOLOGY_TYPE node_type
, unsigned int flags
)
2727 struct media_source
*source
;
2728 struct topo_node
*node
;
2730 if (node_type
== MF_TOPOLOGY_MAX
)
2732 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2734 if ((source
->flags
& flags
) != flags
)
2740 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2742 if (node
->type
== node_type
&& (node
->flags
& flags
) != flags
)
2750 static void session_raise_end_of_presentation(struct media_session
*session
)
2752 if (!(session_nodes_is_mask_set(session
, MF_TOPOLOGY_SOURCESTREAM_NODE
, TOPO_NODE_END_OF_STREAM
)))
2755 if (!(session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
))
2757 if (session_nodes_is_mask_set(session
, MF_TOPOLOGY_MAX
, SOURCE_FLAG_END_OF_PRESENTATION
))
2759 session
->presentation
.flags
|= SESSION_FLAG_END_OF_PRESENTATION
;
2760 session_push_back_command(session
, SESSION_CMD_END
);
2761 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MEEndOfPresentation
, &GUID_NULL
, S_OK
, NULL
);
2766 static void session_handle_end_of_stream(struct media_session
*session
, IMFMediaStream
*stream
)
2768 struct topo_node
*node
;
2770 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream
, MF_TOPOLOGY_SOURCESTREAM_NODE
))
2771 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
2776 session_deliver_sample(session
, stream
, NULL
);
2778 session_raise_end_of_presentation(session
);
2781 static void session_handle_end_of_presentation(struct media_session
*session
, IMFMediaSource
*object
)
2783 struct media_source
*source
;
2785 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2787 if (source
->source
== object
)
2789 if (!(source
->flags
& SOURCE_FLAG_END_OF_PRESENTATION
))
2791 source
->flags
|= SOURCE_FLAG_END_OF_PRESENTATION
;
2792 session_raise_end_of_presentation(session
);
2800 static void session_sink_stream_marker(struct media_session
*session
, IMFStreamSink
*stream_sink
)
2802 struct topo_node
*node
;
2804 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
))
2805 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
2810 node
->flags
|= TOPO_NODE_END_OF_STREAM
;
2812 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
&&
2813 session_nodes_is_mask_set(session
, MF_TOPOLOGY_OUTPUT_NODE
, TOPO_NODE_END_OF_STREAM
))
2815 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
2816 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
2817 session_stop(session
);
2821 static HRESULT WINAPI
session_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
2823 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
2824 IMFMediaEventGenerator
*event_source
;
2825 IMFMediaEvent
*event
= NULL
;
2826 MediaEventType event_type
;
2827 IMFMediaSource
*source
;
2828 IMFMediaStream
*stream
;
2832 if (FAILED(hr
= IMFAsyncResult_GetState(result
, (IUnknown
**)&event_source
)))
2835 if (FAILED(hr
= IMFMediaEventGenerator_EndGetEvent(event_source
, result
, &event
)))
2837 WARN("Failed to get event from %p, hr %#x.\n", event_source
, hr
);
2841 if (FAILED(hr
= IMFMediaEvent_GetType(event
, &event_type
)))
2843 WARN("Failed to get event type, hr %#x.\n", hr
);
2847 value
.vt
= VT_EMPTY
;
2848 if (FAILED(hr
= IMFMediaEvent_GetValue(event
, &value
)))
2850 WARN("Failed to get event value, hr %#x.\n", hr
);
2856 case MESourceStarted
:
2857 case MESourcePaused
:
2858 case MESourceStopped
:
2859 case MEStreamStarted
:
2860 case MEStreamPaused
:
2861 case MEStreamStopped
:
2863 EnterCriticalSection(&session
->cs
);
2864 session_set_source_object_state(session
, (IUnknown
*)event_source
, event_type
);
2865 LeaveCriticalSection(&session
->cs
);
2869 case MEBufferingStarted
:
2870 case MEBufferingStopped
:
2872 EnterCriticalSection(&session
->cs
);
2873 if (session_get_media_source(session
, (IMFMediaSource
*)event_source
))
2875 if (event_type
== MEBufferingStarted
)
2876 IMFPresentationClock_Pause(session
->clock
);
2878 IMFPresentationClock_Start(session
->clock
, PRESENTATION_CURRENT_POSITION
);
2880 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
2882 LeaveCriticalSection(&session
->cs
);
2886 stream
= (IMFMediaStream
*)value
.punkVal
;
2888 if (value
.vt
!= VT_UNKNOWN
|| !stream
)
2890 WARN("Unexpected event value.\n");
2894 if (FAILED(hr
= IMFMediaStream_GetMediaSource(stream
, &source
)))
2897 EnterCriticalSection(&session
->cs
);
2898 if (SUCCEEDED(hr
= session_add_media_stream(session
, source
, stream
)))
2899 hr
= IMFMediaStream_BeginGetEvent(stream
, &session
->events_callback
, (IUnknown
*)stream
);
2900 LeaveCriticalSection(&session
->cs
);
2902 IMFMediaSource_Release(source
);
2905 case MEStreamSinkStarted
:
2906 case MEStreamSinkPaused
:
2907 case MEStreamSinkStopped
:
2908 case MEStreamSinkPrerolled
:
2910 EnterCriticalSection(&session
->cs
);
2911 session_set_sink_stream_state(session
, (IMFStreamSink
*)event_source
, event_type
);
2912 LeaveCriticalSection(&session
->cs
);
2915 case MEStreamSinkMarker
:
2917 EnterCriticalSection(&session
->cs
);
2918 session_sink_stream_marker(session
, (IMFStreamSink
*)event_source
);
2919 LeaveCriticalSection(&session
->cs
);
2922 case MEStreamSinkRequestSample
:
2924 EnterCriticalSection(&session
->cs
);
2925 session_request_sample(session
, (IMFStreamSink
*)event_source
);
2926 LeaveCriticalSection(&session
->cs
);
2931 EnterCriticalSection(&session
->cs
);
2932 session_deliver_sample(session
, (IMFMediaStream
*)event_source
, &value
);
2933 LeaveCriticalSection(&session
->cs
);
2938 EnterCriticalSection(&session
->cs
);
2939 session_handle_end_of_stream(session
, (IMFMediaStream
*)event_source
);
2940 LeaveCriticalSection(&session
->cs
);
2944 case MEEndOfPresentation
:
2946 EnterCriticalSection(&session
->cs
);
2947 session_handle_end_of_presentation(session
, (IMFMediaSource
*)event_source
);
2948 LeaveCriticalSection(&session
->cs
);
2951 case MEAudioSessionGroupingParamChanged
:
2952 case MEAudioSessionIconChanged
:
2953 case MEAudioSessionNameChanged
:
2954 case MEAudioSessionVolumeChanged
:
2956 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
2959 case MEAudioSessionDeviceRemoved
:
2960 case MEAudioSessionDisconnected
:
2961 case MEAudioSessionExclusiveModeOverride
:
2962 case MEAudioSessionFormatChanged
:
2963 case MEAudioSessionServerShutdown
:
2965 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
2967 case MESinkInvalidated
:
2969 EnterCriticalSection(&session
->cs
);
2970 session_sink_invalidated(session
, event_type
== MESinkInvalidated
? event
: NULL
,
2971 (IMFStreamSink
*)event_source
);
2972 LeaveCriticalSection(&session
->cs
);
2979 PropVariantClear(&value
);
2983 IMFMediaEvent_Release(event
);
2985 if (FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(event_source
, iface
, (IUnknown
*)event_source
)))
2986 WARN("Failed to re-subscribe, hr %#x.\n", hr
);
2988 IMFMediaEventGenerator_Release(event_source
);
2993 static const IMFAsyncCallbackVtbl session_events_callback_vtbl
=
2995 session_events_callback_QueryInterface
,
2996 session_events_callback_AddRef
,
2997 session_events_callback_Release
,
2998 session_events_callback_GetParameters
,
2999 session_events_callback_Invoke
,
3002 static HRESULT WINAPI
session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
3004 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
3005 IsEqualIID(riid
, &IID_IUnknown
))
3008 IMFAsyncCallback_AddRef(iface
);
3012 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3014 return E_NOINTERFACE
;
3017 static ULONG WINAPI
session_sink_finalizer_callback_AddRef(IMFAsyncCallback
*iface
)
3019 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3020 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3023 static ULONG WINAPI
session_sink_finalizer_callback_Release(IMFAsyncCallback
*iface
)
3025 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3026 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3029 static HRESULT WINAPI
session_sink_finalizer_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
3034 static HRESULT WINAPI
session_sink_finalizer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
3036 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3037 IMFFinalizableMediaSink
*fin_sink
= NULL
;
3038 BOOL sinks_finalized
= TRUE
;
3039 struct media_sink
*sink
;
3043 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
3046 EnterCriticalSection(&session
->cs
);
3048 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
3050 if (state
== (IUnknown
*)sink
->sink
)
3052 if (FAILED(hr
= IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFFinalizableMediaSink
, (void **)&fin_sink
)))
3053 WARN("Unexpected, missing IMFFinalizableSink, hr %#x.\n", hr
);
3057 sinks_finalized
&= sink
->finalized
;
3058 if (!sinks_finalized
)
3063 IUnknown_Release(state
);
3067 /* Complete session transition, or close prematurely on error. */
3068 if (SUCCEEDED(hr
= IMFFinalizableMediaSink_EndFinalize(fin_sink
, result
)))
3070 sink
->finalized
= TRUE
;
3071 if (sinks_finalized
)
3072 session_set_closed(session
, hr
);
3074 IMFFinalizableMediaSink_Release(fin_sink
);
3077 LeaveCriticalSection(&session
->cs
);
3082 static const IMFAsyncCallbackVtbl session_sink_finalizer_callback_vtbl
=
3084 session_sink_finalizer_callback_QueryInterface
,
3085 session_sink_finalizer_callback_AddRef
,
3086 session_sink_finalizer_callback_Release
,
3087 session_sink_finalizer_callback_GetParameters
,
3088 session_sink_finalizer_callback_Invoke
,
3091 static HRESULT WINAPI
session_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
3093 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3094 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
3097 static ULONG WINAPI
session_rate_support_AddRef(IMFRateSupport
*iface
)
3099 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3100 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3103 static ULONG WINAPI
session_rate_support_Release(IMFRateSupport
*iface
)
3105 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3106 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3109 static HRESULT
session_presentation_object_get_rate(IUnknown
*object
, MFRATE_DIRECTION direction
,
3110 BOOL thin
, BOOL fastest
, float *result
)
3112 IMFRateSupport
*rate_support
;
3116 /* For objects that don't support rate control, it's assumed that only forward direction is allowed, at 1.0f. */
3118 if (FAILED(hr
= MFGetService(object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
, (void **)&rate_support
)))
3120 if (direction
== MFRATE_FORWARD
)
3126 return MF_E_REVERSE_UNSUPPORTED
;
3132 if (SUCCEEDED(hr
= IMFRateSupport_GetFastestRate(rate_support
, direction
, thin
, &rate
)))
3133 *result
= min(fabsf(rate
), *result
);
3137 if (SUCCEEDED(hr
= IMFRateSupport_GetSlowestRate(rate_support
, direction
, thin
, &rate
)))
3138 *result
= max(fabsf(rate
), *result
);
3141 IMFRateSupport_Release(rate_support
);
3146 static HRESULT
session_get_presentation_rate(struct media_session
*session
, MFRATE_DIRECTION direction
,
3147 BOOL thin
, BOOL fastest
, float *result
)
3149 struct media_source
*source
;
3150 struct media_sink
*sink
;
3151 HRESULT hr
= E_POINTER
;
3155 EnterCriticalSection(&session
->cs
);
3157 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
3159 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3161 if (FAILED(hr
= session_presentation_object_get_rate((IUnknown
*)source
->source
, direction
, thin
, fastest
, result
)))
3167 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
3169 if (FAILED(hr
= session_presentation_object_get_rate((IUnknown
*)sink
->sink
, direction
, thin
, fastest
, result
)))
3175 LeaveCriticalSection(&session
->cs
);
3180 static HRESULT WINAPI
session_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
3181 BOOL thin
, float *rate
)
3183 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3185 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
3187 return session_get_presentation_rate(session
, direction
, thin
, FALSE
, rate
);
3190 static HRESULT WINAPI
session_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
3191 BOOL thin
, float *rate
)
3193 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3195 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
3197 return session_get_presentation_rate(session
, direction
, thin
, TRUE
, rate
);
3200 static HRESULT WINAPI
session_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
3201 float *nearest_supported_rate
)
3203 FIXME("%p, %d, %f, %p.\n", iface
, thin
, rate
, nearest_supported_rate
);
3208 static const IMFRateSupportVtbl session_rate_support_vtbl
=
3210 session_rate_support_QueryInterface
,
3211 session_rate_support_AddRef
,
3212 session_rate_support_Release
,
3213 session_rate_support_GetSlowestRate
,
3214 session_rate_support_GetFastestRate
,
3215 session_rate_support_IsRateSupported
,
3218 static HRESULT WINAPI
session_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **obj
)
3220 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3221 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
3224 static ULONG WINAPI
session_rate_control_AddRef(IMFRateControl
*iface
)
3226 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3227 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3230 static ULONG WINAPI
session_rate_control_Release(IMFRateControl
*iface
)
3232 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3233 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3236 static HRESULT WINAPI
session_rate_control_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
3238 FIXME("%p, %d, %f.\n", iface
, thin
, rate
);
3243 static HRESULT WINAPI
session_rate_control_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
3245 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3247 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
3249 return IMFRateControl_GetRate(session
->clock_rate_control
, thin
, rate
);
3252 static const IMFRateControlVtbl session_rate_control_vtbl
=
3254 session_rate_control_QueryInterface
,
3255 session_rate_control_AddRef
,
3256 session_rate_control_Release
,
3257 session_rate_control_SetRate
,
3258 session_rate_control_GetRate
,
3261 /***********************************************************************
3262 * MFCreateMediaSession (mf.@)
3264 HRESULT WINAPI
MFCreateMediaSession(IMFAttributes
*config
, IMFMediaSession
**session
)
3266 BOOL without_quality_manager
= FALSE
;
3267 struct media_session
*object
;
3270 TRACE("%p, %p.\n", config
, session
);
3272 object
= heap_alloc_zero(sizeof(*object
));
3274 return E_OUTOFMEMORY
;
3276 object
->IMFMediaSession_iface
.lpVtbl
= &mfmediasessionvtbl
;
3277 object
->IMFGetService_iface
.lpVtbl
= &session_get_service_vtbl
;
3278 object
->IMFRateSupport_iface
.lpVtbl
= &session_rate_support_vtbl
;
3279 object
->IMFRateControl_iface
.lpVtbl
= &session_rate_control_vtbl
;
3280 object
->commands_callback
.lpVtbl
= &session_commands_callback_vtbl
;
3281 object
->events_callback
.lpVtbl
= &session_events_callback_vtbl
;
3282 object
->sink_finalizer_callback
.lpVtbl
= &session_sink_finalizer_callback_vtbl
;
3283 object
->refcount
= 1;
3284 list_init(&object
->topologies
);
3285 list_init(&object
->commands
);
3286 list_init(&object
->presentation
.sources
);
3287 list_init(&object
->presentation
.sinks
);
3288 list_init(&object
->presentation
.nodes
);
3289 InitializeCriticalSection(&object
->cs
);
3291 if (FAILED(hr
= MFCreateTopology(&object
->presentation
.current_topology
)))
3294 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
3297 if (FAILED(hr
= MFCreatePresentationClock(&object
->clock
)))
3300 if (FAILED(hr
= MFCreateSystemTimeSource(&object
->system_time_source
)))
3303 if (FAILED(hr
= IMFPresentationClock_QueryInterface(object
->clock
, &IID_IMFRateControl
,
3304 (void **)&object
->clock_rate_control
)))
3313 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_TOPOLOADER
, &clsid
)))
3315 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFTopoLoader
,
3316 (void **)&object
->topo_loader
)))
3318 WARN("Failed to create custom topology loader, hr %#x.\n", hr
);
3322 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_QUALITY_MANAGER
, &clsid
)))
3324 if (!(without_quality_manager
= IsEqualGUID(&clsid
, &GUID_NULL
)))
3326 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFQualityManager
,
3327 (void **)&object
->quality_manager
)))
3329 WARN("Failed to create custom quality manager, hr %#x.\n", hr
);
3335 if (!object
->topo_loader
&& FAILED(hr
= MFCreateTopoLoader(&object
->topo_loader
)))
3338 if (!object
->quality_manager
&& !without_quality_manager
&&
3339 FAILED(hr
= MFCreateStandardQualityManager(&object
->quality_manager
)))
3344 *session
= &object
->IMFMediaSession_iface
;
3349 IMFMediaSession_Release(&object
->IMFMediaSession_iface
);
3353 static HRESULT WINAPI
sink_notification_QueryInterface(IUnknown
*iface
, REFIID riid
, void **out
)
3355 if (IsEqualIID(riid
, &IID_IUnknown
))
3358 IUnknown_AddRef(iface
);
3362 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3364 return E_NOINTERFACE
;
3367 static ULONG WINAPI
sink_notification_AddRef(IUnknown
*iface
)
3369 struct sink_notification
*notification
= impl_sink_notification_from_IUnknown(iface
);
3370 ULONG refcount
= InterlockedIncrement(¬ification
->refcount
);
3372 TRACE("%p, refcount %u.\n", iface
, refcount
);
3377 static ULONG WINAPI
sink_notification_Release(IUnknown
*iface
)
3379 struct sink_notification
*notification
= impl_sink_notification_from_IUnknown(iface
);
3380 ULONG refcount
= InterlockedDecrement(¬ification
->refcount
);
3382 TRACE("%p, refcount %u.\n", iface
, refcount
);
3386 IMFClockStateSink_Release(notification
->sink
);
3387 heap_free(notification
);
3393 static const IUnknownVtbl sinknotificationvtbl
=
3395 sink_notification_QueryInterface
,
3396 sink_notification_AddRef
,
3397 sink_notification_Release
,
3400 static void clock_notify_async_sink(struct presentation_clock
*clock
, MFTIME system_time
,
3401 struct clock_state_change_param param
, enum clock_notification notification
, IMFClockStateSink
*sink
)
3403 struct sink_notification
*object
;
3404 IMFAsyncResult
*result
;
3407 object
= heap_alloc(sizeof(*object
));
3411 object
->IUnknown_iface
.lpVtbl
= &sinknotificationvtbl
;
3412 object
->refcount
= 1;
3413 object
->system_time
= system_time
;
3414 object
->param
= param
;
3415 object
->notification
= notification
;
3416 object
->sink
= sink
;
3417 IMFClockStateSink_AddRef(object
->sink
);
3419 hr
= MFCreateAsyncResult(&object
->IUnknown_iface
, &clock
->sink_callback
, NULL
, &result
);
3420 IUnknown_Release(&object
->IUnknown_iface
);
3423 MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD
, result
);
3424 IMFAsyncResult_Release(result
);
3428 static HRESULT WINAPI
present_clock_QueryInterface(IMFPresentationClock
*iface
, REFIID riid
, void **out
)
3430 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3432 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
3434 if (IsEqualIID(riid
, &IID_IMFPresentationClock
) ||
3435 IsEqualIID(riid
, &IID_IMFClock
) ||
3436 IsEqualIID(riid
, &IID_IUnknown
))
3438 *out
= &clock
->IMFPresentationClock_iface
;
3440 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
3442 *out
= &clock
->IMFRateControl_iface
;
3444 else if (IsEqualIID(riid
, &IID_IMFTimer
))
3446 *out
= &clock
->IMFTimer_iface
;
3448 else if (IsEqualIID(riid
, &IID_IMFShutdown
))
3450 *out
= &clock
->IMFShutdown_iface
;
3454 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3456 return E_NOINTERFACE
;
3459 IUnknown_AddRef((IUnknown
*)*out
);
3463 static ULONG WINAPI
present_clock_AddRef(IMFPresentationClock
*iface
)
3465 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3466 ULONG refcount
= InterlockedIncrement(&clock
->refcount
);
3468 TRACE("%p, refcount %u.\n", iface
, refcount
);
3473 static ULONG WINAPI
present_clock_Release(IMFPresentationClock
*iface
)
3475 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3476 ULONG refcount
= InterlockedDecrement(&clock
->refcount
);
3477 struct clock_timer
*timer
, *timer2
;
3478 struct clock_sink
*sink
, *sink2
;
3480 TRACE("%p, refcount %u.\n", iface
, refcount
);
3484 if (clock
->time_source
)
3485 IMFPresentationTimeSource_Release(clock
->time_source
);
3486 if (clock
->time_source_sink
)
3487 IMFClockStateSink_Release(clock
->time_source_sink
);
3488 LIST_FOR_EACH_ENTRY_SAFE(sink
, sink2
, &clock
->sinks
, struct clock_sink
, entry
)
3490 list_remove(&sink
->entry
);
3491 IMFClockStateSink_Release(sink
->state_sink
);
3494 LIST_FOR_EACH_ENTRY_SAFE(timer
, timer2
, &clock
->timers
, struct clock_timer
, entry
)
3496 list_remove(&timer
->entry
);
3497 IUnknown_Release(&timer
->IUnknown_iface
);
3499 DeleteCriticalSection(&clock
->cs
);
3506 static HRESULT WINAPI
present_clock_GetClockCharacteristics(IMFPresentationClock
*iface
, DWORD
*flags
)
3508 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3509 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
3511 TRACE("%p, %p.\n", iface
, flags
);
3513 EnterCriticalSection(&clock
->cs
);
3514 if (clock
->time_source
)
3515 hr
= IMFPresentationTimeSource_GetClockCharacteristics(clock
->time_source
, flags
);
3516 LeaveCriticalSection(&clock
->cs
);
3521 static HRESULT WINAPI
present_clock_GetCorrelatedTime(IMFPresentationClock
*iface
, DWORD reserved
,
3522 LONGLONG
*clock_time
, MFTIME
*system_time
)
3524 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3525 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
3527 TRACE("%p, %#x, %p, %p.\n", iface
, reserved
, clock_time
, system_time
);
3529 EnterCriticalSection(&clock
->cs
);
3530 if (clock
->time_source
)
3531 hr
= IMFPresentationTimeSource_GetCorrelatedTime(clock
->time_source
, reserved
, clock_time
, system_time
);
3532 LeaveCriticalSection(&clock
->cs
);
3537 static HRESULT WINAPI
present_clock_GetContinuityKey(IMFPresentationClock
*iface
, DWORD
*key
)
3539 TRACE("%p, %p.\n", iface
, key
);
3546 static HRESULT WINAPI
present_clock_GetState(IMFPresentationClock
*iface
, DWORD reserved
, MFCLOCK_STATE
*state
)
3548 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3550 TRACE("%p, %#x, %p.\n", iface
, reserved
, state
);
3552 EnterCriticalSection(&clock
->cs
);
3553 *state
= clock
->state
;
3554 LeaveCriticalSection(&clock
->cs
);
3559 static HRESULT WINAPI
present_clock_GetProperties(IMFPresentationClock
*iface
, MFCLOCK_PROPERTIES
*props
)
3561 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3562 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
3564 TRACE("%p, %p.\n", iface
, props
);
3566 EnterCriticalSection(&clock
->cs
);
3567 if (clock
->time_source
)
3568 hr
= IMFPresentationTimeSource_GetProperties(clock
->time_source
, props
);
3569 LeaveCriticalSection(&clock
->cs
);
3574 static HRESULT WINAPI
present_clock_SetTimeSource(IMFPresentationClock
*iface
,
3575 IMFPresentationTimeSource
*time_source
)
3577 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3578 MFCLOCK_PROPERTIES props
;
3579 IMFClock
*source_clock
;
3582 TRACE("%p, %p.\n", iface
, time_source
);
3584 EnterCriticalSection(&clock
->cs
);
3586 if (clock
->time_source
)
3587 IMFPresentationTimeSource_Release(clock
->time_source
);
3588 if (clock
->time_source_sink
)
3589 IMFClockStateSink_Release(clock
->time_source_sink
);
3590 clock
->time_source
= NULL
;
3591 clock
->time_source_sink
= NULL
;
3593 hr
= IMFPresentationTimeSource_QueryInterface(time_source
, &IID_IMFClockStateSink
, (void **)&clock
->time_source_sink
);
3596 clock
->time_source
= time_source
;
3597 IMFPresentationTimeSource_AddRef(clock
->time_source
);
3600 if (SUCCEEDED(IMFPresentationTimeSource_GetUnderlyingClock(time_source
, &source_clock
)))
3602 if (SUCCEEDED(IMFClock_GetProperties(source_clock
, &props
)))
3603 clock
->frequency
= props
.qwClockFrequency
;
3604 IMFClock_Release(source_clock
);
3607 if (!clock
->frequency
)
3608 clock
->frequency
= MFCLOCK_FREQUENCY_HNS
;
3610 LeaveCriticalSection(&clock
->cs
);
3615 static HRESULT WINAPI
present_clock_GetTimeSource(IMFPresentationClock
*iface
,
3616 IMFPresentationTimeSource
**time_source
)
3618 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3621 TRACE("%p, %p.\n", iface
, time_source
);
3624 return E_INVALIDARG
;
3626 EnterCriticalSection(&clock
->cs
);
3627 if (clock
->time_source
)
3629 *time_source
= clock
->time_source
;
3630 IMFPresentationTimeSource_AddRef(*time_source
);
3633 hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
3634 LeaveCriticalSection(&clock
->cs
);
3639 static HRESULT WINAPI
present_clock_GetTime(IMFPresentationClock
*iface
, MFTIME
*time
)
3641 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3642 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
3645 TRACE("%p, %p.\n", iface
, time
);
3650 EnterCriticalSection(&clock
->cs
);
3651 if (clock
->time_source
)
3652 hr
= IMFPresentationTimeSource_GetCorrelatedTime(clock
->time_source
, 0, time
, &systime
);
3653 LeaveCriticalSection(&clock
->cs
);
3658 static HRESULT WINAPI
present_clock_AddClockStateSink(IMFPresentationClock
*iface
, IMFClockStateSink
*state_sink
)
3660 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3661 struct clock_sink
*sink
, *cur
;
3664 TRACE("%p, %p.\n", iface
, state_sink
);
3667 return E_INVALIDARG
;
3669 sink
= heap_alloc(sizeof(*sink
));
3671 return E_OUTOFMEMORY
;
3673 sink
->state_sink
= state_sink
;
3674 IMFClockStateSink_AddRef(sink
->state_sink
);
3676 EnterCriticalSection(&clock
->cs
);
3677 LIST_FOR_EACH_ENTRY(cur
, &clock
->sinks
, struct clock_sink
, entry
)
3679 if (cur
->state_sink
== state_sink
)
3687 static const enum clock_notification notifications
[MFCLOCK_STATE_PAUSED
+ 1] =
3689 /* MFCLOCK_STATE_INVALID */ 0, /* Does not apply */
3690 /* MFCLOCK_STATE_RUNNING */ CLOCK_NOTIFY_START
,
3691 /* MFCLOCK_STATE_STOPPED */ CLOCK_NOTIFY_STOP
,
3692 /* MFCLOCK_STATE_PAUSED */ CLOCK_NOTIFY_PAUSE
,
3694 struct clock_state_change_param param
;
3696 if (!clock
->is_shut_down
&& clock
->state
!= MFCLOCK_STATE_INVALID
)
3698 param
.u
.offset
= clock
->start_offset
;
3699 clock_notify_async_sink(clock
, MFGetSystemTime(), param
, notifications
[clock
->state
], sink
->state_sink
);
3702 list_add_tail(&clock
->sinks
, &sink
->entry
);
3704 LeaveCriticalSection(&clock
->cs
);
3708 IMFClockStateSink_Release(sink
->state_sink
);
3715 static HRESULT WINAPI
present_clock_RemoveClockStateSink(IMFPresentationClock
*iface
,
3716 IMFClockStateSink
*state_sink
)
3718 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3719 struct clock_sink
*sink
;
3721 TRACE("%p, %p.\n", iface
, state_sink
);
3724 return E_INVALIDARG
;
3726 EnterCriticalSection(&clock
->cs
);
3727 LIST_FOR_EACH_ENTRY(sink
, &clock
->sinks
, struct clock_sink
, entry
)
3729 if (sink
->state_sink
== state_sink
)
3731 IMFClockStateSink_Release(sink
->state_sink
);
3732 list_remove(&sink
->entry
);
3737 LeaveCriticalSection(&clock
->cs
);
3742 static HRESULT
clock_call_state_change(MFTIME system_time
, struct clock_state_change_param param
,
3743 enum clock_notification notification
, IMFClockStateSink
*sink
)
3747 switch (notification
)
3749 case CLOCK_NOTIFY_START
:
3750 hr
= IMFClockStateSink_OnClockStart(sink
, system_time
, param
.u
.offset
);
3752 case CLOCK_NOTIFY_STOP
:
3753 hr
= IMFClockStateSink_OnClockStop(sink
, system_time
);
3755 case CLOCK_NOTIFY_PAUSE
:
3756 hr
= IMFClockStateSink_OnClockPause(sink
, system_time
);
3758 case CLOCK_NOTIFY_RESTART
:
3759 hr
= IMFClockStateSink_OnClockRestart(sink
, system_time
);
3761 case CLOCK_NOTIFY_SET_RATE
:
3762 /* System time source does not allow 0.0 rate, presentation clock allows it without raising errors. */
3763 IMFClockStateSink_OnClockSetRate(sink
, system_time
, param
.u
.rate
);
3772 static HRESULT
clock_change_state(struct presentation_clock
*clock
, enum clock_command command
,
3773 struct clock_state_change_param param
)
3775 static const BYTE state_change_is_allowed
[MFCLOCK_STATE_PAUSED
+1][CLOCK_CMD_MAX
] =
3777 /* INVALID */ { 1, 1, 1, 1 },
3778 /* RUNNING */ { 1, 1, 1, 1 },
3779 /* STOPPED */ { 1, 1, 0, 1 },
3780 /* PAUSED */ { 1, 1, 0, 1 },
3782 static const MFCLOCK_STATE states
[CLOCK_CMD_MAX
] =
3784 /* CLOCK_CMD_START */ MFCLOCK_STATE_RUNNING
,
3785 /* CLOCK_CMD_STOP */ MFCLOCK_STATE_STOPPED
,
3786 /* CLOCK_CMD_PAUSE */ MFCLOCK_STATE_PAUSED
,
3787 /* CLOCK_CMD_SET_RATE */ 0, /* Unused */
3789 static const enum clock_notification notifications
[CLOCK_CMD_MAX
] =
3791 /* CLOCK_CMD_START */ CLOCK_NOTIFY_START
,
3792 /* CLOCK_CMD_STOP */ CLOCK_NOTIFY_STOP
,
3793 /* CLOCK_CMD_PAUSE */ CLOCK_NOTIFY_PAUSE
,
3794 /* CLOCK_CMD_SET_RATE */ CLOCK_NOTIFY_SET_RATE
,
3796 enum clock_notification notification
;
3797 struct clock_sink
*sink
;
3798 MFCLOCK_STATE old_state
;
3799 IMFAsyncResult
*result
;
3803 if (!clock
->time_source
)
3804 return MF_E_CLOCK_NO_TIME_SOURCE
;
3806 if (command
!= CLOCK_CMD_SET_RATE
&& clock
->state
== states
[command
] && clock
->state
!= MFCLOCK_STATE_RUNNING
)
3807 return MF_E_CLOCK_STATE_ALREADY_SET
;
3809 if (!state_change_is_allowed
[clock
->state
][command
])
3810 return MF_E_INVALIDREQUEST
;
3812 system_time
= MFGetSystemTime();
3814 if (command
== CLOCK_CMD_START
&& clock
->state
== MFCLOCK_STATE_PAUSED
&&
3815 param
.u
.offset
== PRESENTATION_CURRENT_POSITION
)
3817 notification
= CLOCK_NOTIFY_RESTART
;
3820 notification
= notifications
[command
];
3822 if (FAILED(hr
= clock_call_state_change(system_time
, param
, notification
, clock
->time_source_sink
)))
3825 old_state
= clock
->state
;
3826 if (command
!= CLOCK_CMD_SET_RATE
)
3827 clock
->state
= states
[command
];
3829 /* Dump all pending timer requests immediately on start; otherwise try to cancel scheduled items when
3830 transitioning from running state. */
3831 if ((clock
->state
== MFCLOCK_STATE_RUNNING
) ^ (old_state
== MFCLOCK_STATE_RUNNING
))
3833 struct clock_timer
*timer
, *timer2
;
3835 if (clock
->state
== MFCLOCK_STATE_RUNNING
)
3837 LIST_FOR_EACH_ENTRY_SAFE(timer
, timer2
, &clock
->timers
, struct clock_timer
, entry
)
3839 list_remove(&timer
->entry
);
3840 hr
= MFCreateAsyncResult(&timer
->IUnknown_iface
, &clock
->timer_callback
, NULL
, &result
);
3841 IUnknown_Release(&timer
->IUnknown_iface
);
3844 MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_TIMER
, result
);
3845 IMFAsyncResult_Release(result
);
3851 LIST_FOR_EACH_ENTRY(timer
, &clock
->timers
, struct clock_timer
, entry
)
3855 MFCancelWorkItem(timer
->key
);
3862 LIST_FOR_EACH_ENTRY(sink
, &clock
->sinks
, struct clock_sink
, entry
)
3864 clock_notify_async_sink(clock
, system_time
, param
, notification
, sink
->state_sink
);
3870 static HRESULT WINAPI
present_clock_Start(IMFPresentationClock
*iface
, LONGLONG start_offset
)
3872 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3873 struct clock_state_change_param param
= {{0}};
3876 TRACE("%p, %s.\n", iface
, debugstr_time(start_offset
));
3878 EnterCriticalSection(&clock
->cs
);
3879 clock
->start_offset
= param
.u
.offset
= start_offset
;
3880 hr
= clock_change_state(clock
, CLOCK_CMD_START
, param
);
3881 LeaveCriticalSection(&clock
->cs
);
3886 static HRESULT WINAPI
present_clock_Stop(IMFPresentationClock
*iface
)
3888 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3889 struct clock_state_change_param param
= {{0}};
3892 TRACE("%p.\n", iface
);
3894 EnterCriticalSection(&clock
->cs
);
3895 hr
= clock_change_state(clock
, CLOCK_CMD_STOP
, param
);
3896 LeaveCriticalSection(&clock
->cs
);
3901 static HRESULT WINAPI
present_clock_Pause(IMFPresentationClock
*iface
)
3903 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3904 struct clock_state_change_param param
= {{0}};
3907 TRACE("%p.\n", iface
);
3909 EnterCriticalSection(&clock
->cs
);
3910 hr
= clock_change_state(clock
, CLOCK_CMD_PAUSE
, param
);
3911 LeaveCriticalSection(&clock
->cs
);
3916 static const IMFPresentationClockVtbl presentationclockvtbl
=
3918 present_clock_QueryInterface
,
3919 present_clock_AddRef
,
3920 present_clock_Release
,
3921 present_clock_GetClockCharacteristics
,
3922 present_clock_GetCorrelatedTime
,
3923 present_clock_GetContinuityKey
,
3924 present_clock_GetState
,
3925 present_clock_GetProperties
,
3926 present_clock_SetTimeSource
,
3927 present_clock_GetTimeSource
,
3928 present_clock_GetTime
,
3929 present_clock_AddClockStateSink
,
3930 present_clock_RemoveClockStateSink
,
3931 present_clock_Start
,
3933 present_clock_Pause
,
3936 static HRESULT WINAPI
present_clock_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **out
)
3938 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
3939 return IMFPresentationClock_QueryInterface(&clock
->IMFPresentationClock_iface
, riid
, out
);
3942 static ULONG WINAPI
present_clock_rate_control_AddRef(IMFRateControl
*iface
)
3944 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
3945 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
3948 static ULONG WINAPI
present_clock_rate_control_Release(IMFRateControl
*iface
)
3950 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
3951 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
3954 static HRESULT WINAPI
present_clock_rate_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
3956 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
3957 struct clock_state_change_param param
;
3960 TRACE("%p, %d, %f.\n", iface
, thin
, rate
);
3963 return MF_E_THINNING_UNSUPPORTED
;
3965 EnterCriticalSection(&clock
->cs
);
3966 param
.u
.rate
= rate
;
3967 if (SUCCEEDED(hr
= clock_change_state(clock
, CLOCK_CMD_SET_RATE
, param
)))
3969 LeaveCriticalSection(&clock
->cs
);
3974 static HRESULT WINAPI
present_clock_rate_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
3976 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
3978 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
3981 return E_INVALIDARG
;
3986 EnterCriticalSection(&clock
->cs
);
3987 *rate
= clock
->rate
;
3988 LeaveCriticalSection(&clock
->cs
);
3993 static const IMFRateControlVtbl presentclockratecontrolvtbl
=
3995 present_clock_rate_control_QueryInterface
,
3996 present_clock_rate_control_AddRef
,
3997 present_clock_rate_control_Release
,
3998 present_clock_rate_SetRate
,
3999 present_clock_rate_GetRate
,
4002 static HRESULT WINAPI
present_clock_timer_QueryInterface(IMFTimer
*iface
, REFIID riid
, void **out
)
4004 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4005 return IMFPresentationClock_QueryInterface(&clock
->IMFPresentationClock_iface
, riid
, out
);
4008 static ULONG WINAPI
present_clock_timer_AddRef(IMFTimer
*iface
)
4010 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4011 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
4014 static ULONG WINAPI
present_clock_timer_Release(IMFTimer
*iface
)
4016 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4017 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
4020 static HRESULT
present_clock_schedule_timer(struct presentation_clock
*clock
, DWORD flags
, LONGLONG time
,
4021 struct clock_timer
*timer
)
4023 IMFAsyncResult
*result
;
4024 MFTIME systime
, clocktime
;
4028 if (!(flags
& MFTIMER_RELATIVE
))
4030 if (FAILED(hr
= IMFPresentationTimeSource_GetCorrelatedTime(clock
->time_source
, 0, &clocktime
, &systime
)))
4032 WARN("Failed to get clock time, hr %#x.\n", hr
);
4038 frequency
= clock
->frequency
/ 1000;
4041 /* Scheduled item is using clock instance callback, with timer instance as an object. Clock callback will
4042 call user callback and cleanup timer list. */
4044 if (FAILED(hr
= MFCreateAsyncResult(&timer
->IUnknown_iface
, &clock
->timer_callback
, NULL
, &result
)))
4047 hr
= MFScheduleWorkItemEx(result
, -time
, &timer
->key
);
4048 IMFAsyncResult_Release(result
);
4053 static HRESULT WINAPI
clock_timer_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
4055 if (IsEqualIID(riid
, &IID_IUnknown
))
4058 IUnknown_AddRef(iface
);
4063 return E_NOINTERFACE
;
4066 static ULONG WINAPI
clock_timer_AddRef(IUnknown
*iface
)
4068 struct clock_timer
*timer
= impl_clock_timer_from_IUnknown(iface
);
4069 return InterlockedIncrement(&timer
->refcount
);
4072 static ULONG WINAPI
clock_timer_Release(IUnknown
*iface
)
4074 struct clock_timer
*timer
= impl_clock_timer_from_IUnknown(iface
);
4075 ULONG refcount
= InterlockedDecrement(&timer
->refcount
);
4079 IMFAsyncResult_Release(timer
->result
);
4080 IMFAsyncCallback_Release(timer
->callback
);
4087 static const IUnknownVtbl clock_timer_vtbl
=
4089 clock_timer_QueryInterface
,
4091 clock_timer_Release
,
4094 static HRESULT WINAPI
present_clock_timer_SetTimer(IMFTimer
*iface
, DWORD flags
, LONGLONG time
,
4095 IMFAsyncCallback
*callback
, IUnknown
*state
, IUnknown
**cancel_key
)
4097 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4098 struct clock_timer
*clock_timer
;
4101 TRACE("%p, %#x, %s, %p, %p, %p.\n", iface
, flags
, debugstr_time(time
), callback
, state
, cancel_key
);
4103 if (!(clock_timer
= heap_alloc_zero(sizeof(*clock_timer
))))
4104 return E_OUTOFMEMORY
;
4106 if (FAILED(hr
= MFCreateAsyncResult(NULL
, NULL
, state
, &clock_timer
->result
)))
4108 heap_free(clock_timer
);
4112 clock_timer
->IUnknown_iface
.lpVtbl
= &clock_timer_vtbl
;
4113 clock_timer
->refcount
= 1;
4114 clock_timer
->callback
= callback
;
4115 IMFAsyncCallback_AddRef(clock_timer
->callback
);
4117 EnterCriticalSection(&clock
->cs
);
4119 if (clock
->state
== MFCLOCK_STATE_RUNNING
)
4120 hr
= present_clock_schedule_timer(clock
, flags
, time
, clock_timer
);
4121 else if (clock
->state
== MFCLOCK_STATE_STOPPED
)
4122 hr
= MF_S_CLOCK_STOPPED
;
4126 list_add_tail(&clock
->timers
, &clock_timer
->entry
);
4129 *cancel_key
= &clock_timer
->IUnknown_iface
;
4130 IUnknown_AddRef(*cancel_key
);
4134 LeaveCriticalSection(&clock
->cs
);
4137 IUnknown_Release(&clock_timer
->IUnknown_iface
);
4142 static HRESULT WINAPI
present_clock_timer_CancelTimer(IMFTimer
*iface
, IUnknown
*cancel_key
)
4144 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4145 struct clock_timer
*timer
;
4147 TRACE("%p, %p.\n", iface
, cancel_key
);
4149 EnterCriticalSection(&clock
->cs
);
4151 LIST_FOR_EACH_ENTRY(timer
, &clock
->timers
, struct clock_timer
, entry
)
4153 if (&timer
->IUnknown_iface
== cancel_key
)
4155 list_remove(&timer
->entry
);
4158 MFCancelWorkItem(timer
->key
);
4161 IUnknown_Release(&timer
->IUnknown_iface
);
4166 LeaveCriticalSection(&clock
->cs
);
4171 static const IMFTimerVtbl presentclocktimervtbl
=
4173 present_clock_timer_QueryInterface
,
4174 present_clock_timer_AddRef
,
4175 present_clock_timer_Release
,
4176 present_clock_timer_SetTimer
,
4177 present_clock_timer_CancelTimer
,
4180 static HRESULT WINAPI
present_clock_shutdown_QueryInterface(IMFShutdown
*iface
, REFIID riid
, void **out
)
4182 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4183 return IMFPresentationClock_QueryInterface(&clock
->IMFPresentationClock_iface
, riid
, out
);
4186 static ULONG WINAPI
present_clock_shutdown_AddRef(IMFShutdown
*iface
)
4188 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4189 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
4192 static ULONG WINAPI
present_clock_shutdown_Release(IMFShutdown
*iface
)
4194 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4195 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
4198 static HRESULT WINAPI
present_clock_shutdown_Shutdown(IMFShutdown
*iface
)
4200 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4202 TRACE("%p.\n", iface
);
4204 EnterCriticalSection(&clock
->cs
);
4205 clock
->is_shut_down
= TRUE
;
4206 LeaveCriticalSection(&clock
->cs
);
4211 static HRESULT WINAPI
present_clock_shutdown_GetShutdownStatus(IMFShutdown
*iface
, MFSHUTDOWN_STATUS
*status
)
4213 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4216 TRACE("%p, %p.\n", iface
, status
);
4219 return E_INVALIDARG
;
4221 EnterCriticalSection(&clock
->cs
);
4222 if (clock
->is_shut_down
)
4223 *status
= MFSHUTDOWN_COMPLETED
;
4225 hr
= MF_E_INVALIDREQUEST
;
4226 LeaveCriticalSection(&clock
->cs
);
4231 static const IMFShutdownVtbl presentclockshutdownvtbl
=
4233 present_clock_shutdown_QueryInterface
,
4234 present_clock_shutdown_AddRef
,
4235 present_clock_shutdown_Release
,
4236 present_clock_shutdown_Shutdown
,
4237 present_clock_shutdown_GetShutdownStatus
,
4240 static HRESULT WINAPI
present_clock_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **out
)
4242 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
4243 IsEqualIID(riid
, &IID_IUnknown
))
4246 IMFAsyncCallback_AddRef(iface
);
4250 WARN("Unsupported %s.\n", wine_dbgstr_guid(riid
));
4252 return E_NOINTERFACE
;
4255 static ULONG WINAPI
present_clock_sink_callback_AddRef(IMFAsyncCallback
*iface
)
4257 struct presentation_clock
*clock
= impl_from_sink_callback_IMFAsyncCallback(iface
);
4258 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
4261 static ULONG WINAPI
present_clock_sink_callback_Release(IMFAsyncCallback
*iface
)
4263 struct presentation_clock
*clock
= impl_from_sink_callback_IMFAsyncCallback(iface
);
4264 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
4267 static HRESULT WINAPI
present_clock_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
4272 static HRESULT WINAPI
present_clock_sink_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
4274 struct sink_notification
*data
;
4278 if (FAILED(hr
= IMFAsyncResult_GetObject(result
, &object
)))
4281 data
= impl_sink_notification_from_IUnknown(object
);
4283 clock_call_state_change(data
->system_time
, data
->param
, data
->notification
, data
->sink
);
4285 IUnknown_Release(object
);
4290 static const IMFAsyncCallbackVtbl presentclocksinkcallbackvtbl
=
4292 present_clock_callback_QueryInterface
,
4293 present_clock_sink_callback_AddRef
,
4294 present_clock_sink_callback_Release
,
4295 present_clock_callback_GetParameters
,
4296 present_clock_sink_callback_Invoke
,
4299 static ULONG WINAPI
present_clock_timer_callback_AddRef(IMFAsyncCallback
*iface
)
4301 struct presentation_clock
*clock
= impl_from_timer_callback_IMFAsyncCallback(iface
);
4302 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
4305 static ULONG WINAPI
present_clock_timer_callback_Release(IMFAsyncCallback
*iface
)
4307 struct presentation_clock
*clock
= impl_from_timer_callback_IMFAsyncCallback(iface
);
4308 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
4311 static HRESULT WINAPI
present_clock_timer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
4313 struct presentation_clock
*clock
= impl_from_timer_callback_IMFAsyncCallback(iface
);
4314 struct clock_timer
*timer
;
4318 if (FAILED(hr
= IMFAsyncResult_GetObject(result
, &object
)))
4321 timer
= impl_clock_timer_from_IUnknown(object
);
4323 EnterCriticalSection(&clock
->cs
);
4324 list_remove(&timer
->entry
);
4325 IUnknown_Release(&timer
->IUnknown_iface
);
4326 LeaveCriticalSection(&clock
->cs
);
4328 IMFAsyncCallback_Invoke(timer
->callback
, timer
->result
);
4330 IUnknown_Release(object
);
4335 static const IMFAsyncCallbackVtbl presentclocktimercallbackvtbl
=
4337 present_clock_callback_QueryInterface
,
4338 present_clock_timer_callback_AddRef
,
4339 present_clock_timer_callback_Release
,
4340 present_clock_callback_GetParameters
,
4341 present_clock_timer_callback_Invoke
,
4344 /***********************************************************************
4345 * MFCreatePresentationClock (mf.@)
4347 HRESULT WINAPI
MFCreatePresentationClock(IMFPresentationClock
**clock
)
4349 struct presentation_clock
*object
;
4351 TRACE("%p.\n", clock
);
4353 object
= heap_alloc_zero(sizeof(*object
));
4355 return E_OUTOFMEMORY
;
4357 object
->IMFPresentationClock_iface
.lpVtbl
= &presentationclockvtbl
;
4358 object
->IMFRateControl_iface
.lpVtbl
= &presentclockratecontrolvtbl
;
4359 object
->IMFTimer_iface
.lpVtbl
= &presentclocktimervtbl
;
4360 object
->IMFShutdown_iface
.lpVtbl
= &presentclockshutdownvtbl
;
4361 object
->sink_callback
.lpVtbl
= &presentclocksinkcallbackvtbl
;
4362 object
->timer_callback
.lpVtbl
= &presentclocktimercallbackvtbl
;
4363 object
->refcount
= 1;
4364 list_init(&object
->sinks
);
4365 list_init(&object
->timers
);
4366 object
->rate
= 1.0f
;
4367 InitializeCriticalSection(&object
->cs
);
4369 *clock
= &object
->IMFPresentationClock_iface
;
4374 static HRESULT WINAPI
standard_quality_manager_QueryInterface(IMFQualityManager
*iface
, REFIID riid
, void **out
)
4376 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
4378 if (IsEqualIID(riid
, &IID_IMFQualityManager
) ||
4379 IsEqualIID(riid
, &IID_IUnknown
))
4382 IMFQualityManager_AddRef(iface
);
4386 WARN("Unsupported %s.\n", debugstr_guid(riid
));
4388 return E_NOINTERFACE
;
4391 static ULONG WINAPI
standard_quality_manager_AddRef(IMFQualityManager
*iface
)
4393 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
4394 ULONG refcount
= InterlockedIncrement(&manager
->refcount
);
4396 TRACE("%p, refcount %u.\n", iface
, refcount
);
4401 static ULONG WINAPI
standard_quality_manager_Release(IMFQualityManager
*iface
)
4403 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
4404 ULONG refcount
= InterlockedDecrement(&manager
->refcount
);
4406 TRACE("%p, refcount %u.\n", iface
, refcount
);
4416 static HRESULT WINAPI
standard_quality_manager_NotifyTopology(IMFQualityManager
*iface
, IMFTopology
*topology
)
4418 FIXME("%p, %p stub.\n", iface
, topology
);
4423 static HRESULT WINAPI
standard_quality_manager_NotifyPresentationClock(IMFQualityManager
*iface
,
4424 IMFPresentationClock
*clock
)
4426 FIXME("%p, %p stub.\n", iface
, clock
);
4431 static HRESULT WINAPI
standard_quality_manager_NotifyProcessInput(IMFQualityManager
*iface
, IMFTopologyNode
*node
,
4432 LONG input_index
, IMFSample
*sample
)
4434 FIXME("%p, %p, %d, %p stub.\n", iface
, node
, input_index
, sample
);
4439 static HRESULT WINAPI
standard_quality_manager_NotifyProcessOutput(IMFQualityManager
*iface
, IMFTopologyNode
*node
,
4440 LONG output_index
, IMFSample
*sample
)
4442 FIXME("%p, %p, %d, %p stub.\n", iface
, node
, output_index
, sample
);
4447 static HRESULT WINAPI
standard_quality_manager_NotifyQualityEvent(IMFQualityManager
*iface
, IUnknown
*object
,
4448 IMFMediaEvent
*event
)
4450 FIXME("%p, %p, %p stub.\n", iface
, object
, event
);
4455 static HRESULT WINAPI
standard_quality_manager_Shutdown(IMFQualityManager
*iface
)
4457 FIXME("%p stub.\n", iface
);
4462 static IMFQualityManagerVtbl standard_quality_manager_vtbl
=
4464 standard_quality_manager_QueryInterface
,
4465 standard_quality_manager_AddRef
,
4466 standard_quality_manager_Release
,
4467 standard_quality_manager_NotifyTopology
,
4468 standard_quality_manager_NotifyPresentationClock
,
4469 standard_quality_manager_NotifyProcessInput
,
4470 standard_quality_manager_NotifyProcessOutput
,
4471 standard_quality_manager_NotifyQualityEvent
,
4472 standard_quality_manager_Shutdown
,
4475 HRESULT WINAPI
MFCreateStandardQualityManager(IMFQualityManager
**manager
)
4477 struct quality_manager
*object
;
4479 TRACE("%p.\n", manager
);
4481 object
= heap_alloc_zero(sizeof(*object
));
4483 return E_OUTOFMEMORY
;
4485 object
->IMFQualityManager_iface
.lpVtbl
= &standard_quality_manager_vtbl
;
4486 object
->refcount
= 1;
4488 *manager
= &object
->IMFQualityManager_iface
;