mf/session: Add a stub for IMFTopologyNodeAttributeEditor.
[wine.git] / dlls / mf / session.c
blob5034255339cc81048b2dde82bf1c361312642d33
1 /*
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
19 #include <stdarg.h>
20 #include <math.h>
22 #define COBJMACROS
24 #include "windef.h"
25 #include "winbase.h"
26 #include "mfidl.h"
27 #include "evr.h"
29 #include "wine/debug.h"
30 #include "wine/heap.h"
31 #include "wine/list.h"
33 #include "mf_private.h"
35 #include "initguid.h"
37 DEFINE_GUID(_MF_TOPONODE_IMFActivate, 0x33706f4a, 0x309a, 0x49be, 0xa8, 0xdd, 0xe7, 0xc0, 0x87, 0x5e, 0xb6, 0x79);
39 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
41 enum session_command
43 SESSION_CMD_CLEAR_TOPOLOGIES,
44 SESSION_CMD_CLOSE,
45 SESSION_CMD_SET_TOPOLOGY,
46 SESSION_CMD_START,
47 SESSION_CMD_PAUSE,
48 SESSION_CMD_STOP,
49 /* Internally used commands. */
50 SESSION_CMD_END,
51 SESSION_CMD_QM_NOTIFY_TOPOLOGY,
52 SESSION_CMD_SA_READY,
55 struct session_op
57 IUnknown IUnknown_iface;
58 LONG refcount;
59 enum session_command command;
60 union
62 struct
64 DWORD flags;
65 IMFTopology *topology;
66 } set_topology;
67 struct
69 GUID time_format;
70 PROPVARIANT start_position;
71 } start;
72 struct
74 IMFTopology *topology;
75 } notify_topology;
76 struct
78 TOPOID node_id;
79 } sa_ready;
80 } u;
81 struct list entry;
84 struct queued_topology
86 struct list entry;
87 IMFTopology *topology;
88 MF_TOPOSTATUS status;
91 enum session_state
93 SESSION_STATE_STOPPED = 0,
94 SESSION_STATE_STARTING_SOURCES,
95 SESSION_STATE_PREROLLING_SINKS,
96 SESSION_STATE_STARTING_SINKS,
97 SESSION_STATE_STARTED,
98 SESSION_STATE_PAUSING_SINKS,
99 SESSION_STATE_PAUSING_SOURCES,
100 SESSION_STATE_PAUSED,
101 SESSION_STATE_STOPPING_SINKS,
102 SESSION_STATE_STOPPING_SOURCES,
103 SESSION_STATE_FINALIZING_SINKS,
104 SESSION_STATE_CLOSED,
105 SESSION_STATE_SHUT_DOWN,
108 enum object_state
110 OBJ_STATE_STOPPED = 0,
111 OBJ_STATE_STARTED,
112 OBJ_STATE_PAUSED,
113 OBJ_STATE_PREROLLED,
114 OBJ_STATE_INVALID,
117 enum media_source_flags
119 SOURCE_FLAG_END_OF_PRESENTATION = 0x1,
122 struct media_source
124 struct list entry;
125 IMFMediaSource *source;
126 IMFPresentationDescriptor *pd;
127 enum object_state state;
128 unsigned int flags;
131 struct media_sink
133 struct list entry;
134 IMFMediaSink *sink;
135 IMFMediaSinkPreroll *preroll;
136 IMFMediaEventGenerator *event_generator;
137 BOOL finalized;
140 struct sample
142 struct list entry;
143 IMFSample *sample;
146 struct transform_stream
148 struct list samples;
149 unsigned int requests;
152 enum topo_node_flags
154 TOPO_NODE_END_OF_STREAM = 0x1,
157 struct topo_node
159 struct list entry;
160 struct media_session *session;
161 MF_TOPOLOGY_TYPE type;
162 TOPOID node_id;
163 IMFTopologyNode *node;
164 enum object_state state;
165 unsigned int flags;
166 union
168 IMFMediaStream *source_stream;
169 IMFStreamSink *sink_stream;
170 IMFTransform *transform;
171 IUnknown *object;
172 } object;
174 union
176 struct
178 IMFMediaSource *source;
179 unsigned int stream_id;
180 } source;
181 struct
183 unsigned int requests;
184 IMFVideoSampleAllocatorNotify notify_cb;
185 IMFVideoSampleAllocator *allocator;
186 IMFVideoSampleAllocatorCallback *allocator_cb;
187 } sink;
188 struct
190 struct transform_stream *inputs;
191 unsigned int *input_map;
192 unsigned int input_count;
194 struct transform_stream *outputs;
195 unsigned int *output_map;
196 unsigned int output_count;
197 } transform;
198 } u;
201 enum presentation_flags
203 SESSION_FLAG_SOURCES_SUBSCRIBED = 0x1,
204 SESSION_FLAG_PRESENTATION_CLOCK_SET = 0x2,
205 SESSION_FLAG_FINALIZE_SINKS = 0x4,
206 SESSION_FLAG_NEEDS_PREROLL = 0x8,
207 SESSION_FLAG_END_OF_PRESENTATION = 0x10,
210 struct media_session
212 IMFMediaSession IMFMediaSession_iface;
213 IMFGetService IMFGetService_iface;
214 IMFRateSupport IMFRateSupport_iface;
215 IMFRateControl IMFRateControl_iface;
216 IMFTopologyNodeAttributeEditor IMFTopologyNodeAttributeEditor_iface;
217 IMFAsyncCallback commands_callback;
218 IMFAsyncCallback events_callback;
219 IMFAsyncCallback sink_finalizer_callback;
220 LONG refcount;
221 IMFMediaEventQueue *event_queue;
222 IMFPresentationClock *clock;
223 IMFPresentationTimeSource *system_time_source;
224 IMFRateControl *clock_rate_control;
225 IMFTopoLoader *topo_loader;
226 IMFQualityManager *quality_manager;
227 struct
229 IMFTopology *current_topology;
230 MF_TOPOSTATUS topo_status;
231 MFTIME clock_stop_time;
232 unsigned int flags;
233 struct list sources;
234 struct list sinks;
235 struct list nodes;
237 /* Latest Start() arguments. */
238 GUID time_format;
239 PROPVARIANT start_position;
240 } presentation;
241 struct list topologies;
242 struct list commands;
243 enum session_state state;
244 DWORD caps;
245 CRITICAL_SECTION cs;
248 struct clock_sink
250 struct list entry;
251 IMFClockStateSink *state_sink;
254 enum clock_command
256 CLOCK_CMD_START = 0,
257 CLOCK_CMD_STOP,
258 CLOCK_CMD_PAUSE,
259 CLOCK_CMD_SET_RATE,
260 CLOCK_CMD_MAX,
263 enum clock_notification
265 CLOCK_NOTIFY_START,
266 CLOCK_NOTIFY_STOP,
267 CLOCK_NOTIFY_PAUSE,
268 CLOCK_NOTIFY_RESTART,
269 CLOCK_NOTIFY_SET_RATE,
272 struct clock_state_change_param
274 union
276 LONGLONG offset;
277 float rate;
278 } u;
281 struct sink_notification
283 IUnknown IUnknown_iface;
284 LONG refcount;
285 MFTIME system_time;
286 struct clock_state_change_param param;
287 enum clock_notification notification;
288 IMFClockStateSink *sink;
291 struct clock_timer
293 IUnknown IUnknown_iface;
294 LONG refcount;
295 IMFAsyncResult *result;
296 IMFAsyncCallback *callback;
297 MFWORKITEM_KEY key;
298 struct list entry;
301 struct presentation_clock
303 IMFPresentationClock IMFPresentationClock_iface;
304 IMFRateControl IMFRateControl_iface;
305 IMFTimer IMFTimer_iface;
306 IMFShutdown IMFShutdown_iface;
307 IMFAsyncCallback sink_callback;
308 IMFAsyncCallback timer_callback;
309 LONG refcount;
310 IMFPresentationTimeSource *time_source;
311 IMFClockStateSink *time_source_sink;
312 MFCLOCK_STATE state;
313 LONGLONG start_offset;
314 struct list sinks;
315 struct list timers;
316 float rate;
317 LONGLONG frequency;
318 CRITICAL_SECTION cs;
319 BOOL is_shut_down;
322 struct quality_manager
324 IMFQualityManager IMFQualityManager_iface;
325 LONG refcount;
327 IMFPresentationClock *clock;
328 CRITICAL_SECTION cs;
331 static inline struct media_session *impl_from_IMFMediaSession(IMFMediaSession *iface)
333 return CONTAINING_RECORD(iface, struct media_session, IMFMediaSession_iface);
336 static struct media_session *impl_from_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
338 return CONTAINING_RECORD(iface, struct media_session, commands_callback);
341 static struct media_session *impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
343 return CONTAINING_RECORD(iface, struct media_session, events_callback);
346 static struct media_session *impl_from_sink_finalizer_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
348 return CONTAINING_RECORD(iface, struct media_session, sink_finalizer_callback);
351 static struct media_session *impl_from_IMFGetService(IMFGetService *iface)
353 return CONTAINING_RECORD(iface, struct media_session, IMFGetService_iface);
356 static struct media_session *impl_session_from_IMFRateSupport(IMFRateSupport *iface)
358 return CONTAINING_RECORD(iface, struct media_session, IMFRateSupport_iface);
361 static struct media_session *impl_session_from_IMFRateControl(IMFRateControl *iface)
363 return CONTAINING_RECORD(iface, struct media_session, IMFRateControl_iface);
366 static struct media_session *impl_session_from_IMFTopologyNodeAttributeEditor(IMFTopologyNodeAttributeEditor *iface)
368 return CONTAINING_RECORD(iface, struct media_session, IMFTopologyNodeAttributeEditor_iface);
371 static struct session_op *impl_op_from_IUnknown(IUnknown *iface)
373 return CONTAINING_RECORD(iface, struct session_op, IUnknown_iface);
376 static struct presentation_clock *impl_from_IMFPresentationClock(IMFPresentationClock *iface)
378 return CONTAINING_RECORD(iface, struct presentation_clock, IMFPresentationClock_iface);
381 static struct presentation_clock *impl_from_IMFRateControl(IMFRateControl *iface)
383 return CONTAINING_RECORD(iface, struct presentation_clock, IMFRateControl_iface);
386 static struct presentation_clock *impl_from_IMFTimer(IMFTimer *iface)
388 return CONTAINING_RECORD(iface, struct presentation_clock, IMFTimer_iface);
391 static struct presentation_clock *impl_from_IMFShutdown(IMFShutdown *iface)
393 return CONTAINING_RECORD(iface, struct presentation_clock, IMFShutdown_iface);
396 static struct presentation_clock *impl_from_sink_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
398 return CONTAINING_RECORD(iface, struct presentation_clock, sink_callback);
401 static struct presentation_clock *impl_from_timer_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
403 return CONTAINING_RECORD(iface, struct presentation_clock, timer_callback);
406 static struct clock_timer *impl_clock_timer_from_IUnknown(IUnknown *iface)
408 return CONTAINING_RECORD(iface, struct clock_timer, IUnknown_iface);
411 static struct sink_notification *impl_sink_notification_from_IUnknown(IUnknown *iface)
413 return CONTAINING_RECORD(iface, struct sink_notification, IUnknown_iface);
416 static struct quality_manager *impl_from_IMFQualityManager(IMFQualityManager *iface)
418 return CONTAINING_RECORD(iface, struct quality_manager, IMFQualityManager_iface);
421 static struct topo_node *impl_node_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify *iface)
423 return CONTAINING_RECORD(iface, struct topo_node, u.sink.notify_cb);
426 /* IMFLocalMFTRegistration */
427 static HRESULT WINAPI local_mft_registration_QueryInterface(IMFLocalMFTRegistration *iface, REFIID riid, void **obj)
429 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
431 if (IsEqualIID(riid, &IID_IMFLocalMFTRegistration) ||
432 IsEqualIID(riid, &IID_IUnknown))
434 *obj = iface;
435 IMFLocalMFTRegistration_AddRef(iface);
436 return S_OK;
439 WARN("Unexpected %s.\n", debugstr_guid(riid));
440 *obj = NULL;
441 return E_NOINTERFACE;
444 static ULONG WINAPI local_mft_registration_AddRef(IMFLocalMFTRegistration *iface)
446 return 2;
449 static ULONG WINAPI local_mft_registration_Release(IMFLocalMFTRegistration *iface)
451 return 1;
454 static HRESULT WINAPI local_mft_registration_RegisterMFTs(IMFLocalMFTRegistration *iface, MFT_REGISTRATION_INFO *info,
455 DWORD count)
457 HRESULT hr = S_OK;
458 DWORD i;
460 TRACE("%p, %p, %u.\n", iface, info, count);
462 for (i = 0; i < count; ++i)
464 if (FAILED(hr = MFTRegisterLocalByCLSID(&info[i].clsid, &info[i].guidCategory, info[i].pszName,
465 info[i].uiFlags, info[i].cInTypes, info[i].pInTypes, info[i].cOutTypes, info[i].pOutTypes)))
467 break;
471 return hr;
474 static const IMFLocalMFTRegistrationVtbl local_mft_registration_vtbl =
476 local_mft_registration_QueryInterface,
477 local_mft_registration_AddRef,
478 local_mft_registration_Release,
479 local_mft_registration_RegisterMFTs,
482 static IMFLocalMFTRegistration local_mft_registration = { &local_mft_registration_vtbl };
484 static HRESULT WINAPI session_op_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
486 if (IsEqualIID(riid, &IID_IUnknown))
488 *obj = iface;
489 IUnknown_AddRef(iface);
490 return S_OK;
493 *obj = NULL;
494 return E_NOINTERFACE;
497 static ULONG WINAPI session_op_AddRef(IUnknown *iface)
499 struct session_op *op = impl_op_from_IUnknown(iface);
500 ULONG refcount = InterlockedIncrement(&op->refcount);
502 TRACE("%p, refcount %u.\n", iface, refcount);
504 return refcount;
507 static ULONG WINAPI session_op_Release(IUnknown *iface)
509 struct session_op *op = impl_op_from_IUnknown(iface);
510 ULONG refcount = InterlockedDecrement(&op->refcount);
512 TRACE("%p, refcount %u.\n", iface, refcount);
514 if (!refcount)
516 switch (op->command)
518 case SESSION_CMD_SET_TOPOLOGY:
519 if (op->u.set_topology.topology)
520 IMFTopology_Release(op->u.set_topology.topology);
521 break;
522 case SESSION_CMD_START:
523 PropVariantClear(&op->u.start.start_position);
524 break;
525 case SESSION_CMD_QM_NOTIFY_TOPOLOGY:
526 if (op->u.notify_topology.topology)
527 IMFTopology_Release(op->u.notify_topology.topology);
528 break;
529 default:
532 heap_free(op);
535 return refcount;
538 static IUnknownVtbl session_op_vtbl =
540 session_op_QueryInterface,
541 session_op_AddRef,
542 session_op_Release,
545 static HRESULT create_session_op(enum session_command command, struct session_op **ret)
547 struct session_op *op;
549 if (!(op = heap_alloc_zero(sizeof(*op))))
550 return E_OUTOFMEMORY;
552 op->IUnknown_iface.lpVtbl = &session_op_vtbl;
553 op->refcount = 1;
554 op->command = command;
556 *ret = op;
558 return S_OK;
561 static HRESULT session_is_shut_down(struct media_session *session)
563 return session->state == SESSION_STATE_SHUT_DOWN ? MF_E_SHUTDOWN : S_OK;
566 static void session_push_back_command(struct media_session *session, enum session_command command)
568 struct session_op *op;
570 if (SUCCEEDED(create_session_op(command, &op)))
571 list_add_head(&session->commands, &op->entry);
574 static HRESULT session_submit_command(struct media_session *session, struct session_op *op)
576 HRESULT hr;
578 EnterCriticalSection(&session->cs);
579 if (SUCCEEDED(hr = session_is_shut_down(session)))
581 if (list_empty(&session->commands))
582 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface);
583 list_add_tail(&session->commands, &op->entry);
584 IUnknown_AddRef(&op->IUnknown_iface);
586 LeaveCriticalSection(&session->cs);
588 return hr;
591 static HRESULT session_submit_simple_command(struct media_session *session, enum session_command command)
593 struct session_op *op;
594 HRESULT hr;
596 if (FAILED(hr = create_session_op(command, &op)))
597 return hr;
599 hr = session_submit_command(session, op);
600 IUnknown_Release(&op->IUnknown_iface);
601 return hr;
604 static void session_clear_topologies(struct media_session *session)
606 struct queued_topology *ptr, *next;
608 LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &session->topologies, struct queued_topology, entry)
610 list_remove(&ptr->entry);
611 IMFTopology_Release(ptr->topology);
612 heap_free(ptr);
616 static void session_set_topo_status(struct media_session *session, HRESULT status,
617 MF_TOPOSTATUS topo_status)
619 IMFMediaEvent *event;
620 PROPVARIANT param;
622 if (topo_status == MF_TOPOSTATUS_INVALID)
623 return;
625 if (list_empty(&session->topologies))
627 FIXME("Unexpectedly empty topology queue.\n");
628 return;
631 if (topo_status > session->presentation.topo_status)
633 struct queued_topology *topology = LIST_ENTRY(list_head(&session->topologies), struct queued_topology, entry);
635 param.vt = VT_UNKNOWN;
636 param.punkVal = (IUnknown *)topology->topology;
638 if (FAILED(MFCreateMediaEvent(MESessionTopologyStatus, &GUID_NULL, status, &param, &event)))
639 return;
641 session->presentation.topo_status = topo_status;
643 IMFMediaEvent_SetUINT32(event, &MF_EVENT_TOPOLOGY_STATUS, topo_status);
644 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
645 IMFMediaEvent_Release(event);
649 static HRESULT session_bind_output_nodes(IMFTopology *topology)
651 MF_TOPOLOGY_TYPE node_type;
652 IMFStreamSink *stream_sink;
653 IMFMediaSink *media_sink;
654 WORD node_count = 0, i;
655 IMFTopologyNode *node;
656 IMFActivate *activate;
657 UINT32 stream_id;
658 IUnknown *object;
659 HRESULT hr;
661 hr = IMFTopology_GetNodeCount(topology, &node_count);
663 for (i = 0; i < node_count; ++i)
665 if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
666 break;
668 if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type)) || node_type != MF_TOPOLOGY_OUTPUT_NODE)
670 IMFTopologyNode_Release(node);
671 continue;
674 if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object)))
676 stream_sink = NULL;
677 if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&stream_sink)))
679 if (SUCCEEDED(hr = IUnknown_QueryInterface(object, &IID_IMFActivate, (void **)&activate)))
681 if (SUCCEEDED(hr = IMFActivate_ActivateObject(activate, &IID_IMFMediaSink, (void **)&media_sink)))
683 if (FAILED(IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_STREAMID, &stream_id)))
684 stream_id = 0;
686 stream_sink = NULL;
687 if (FAILED(IMFMediaSink_GetStreamSinkById(media_sink, stream_id, &stream_sink)))
688 hr = IMFMediaSink_AddStreamSink(media_sink, stream_id, NULL, &stream_sink);
690 if (stream_sink)
691 hr = IMFTopologyNode_SetObject(node, (IUnknown *)stream_sink);
693 IMFMediaSink_Release(media_sink);
696 if (SUCCEEDED(hr))
697 IMFTopologyNode_SetUnknown(node, &_MF_TOPONODE_IMFActivate, (IUnknown *)activate);
699 IMFActivate_Release(activate);
703 if (stream_sink)
704 IMFStreamSink_Release(stream_sink);
705 IUnknown_Release(object);
708 IMFTopologyNode_Release(node);
711 return hr;
714 static void session_set_caps(struct media_session *session, DWORD caps)
716 DWORD delta = session->caps ^ caps;
717 IMFMediaEvent *event;
719 /* Delta is documented to reflect rate value changes as well, but it's not clear what to compare
720 them to, since session always queries for current object rates. */
721 if (!delta)
722 return;
724 session->caps = caps;
726 if (FAILED(MFCreateMediaEvent(MESessionCapabilitiesChanged, &GUID_NULL, S_OK, NULL, &event)))
727 return;
729 IMFMediaEvent_SetUINT32(event, &MF_EVENT_SESSIONCAPS, caps);
730 IMFMediaEvent_SetUINT32(event, &MF_EVENT_SESSIONCAPS_DELTA, delta);
732 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
733 IMFMediaEvent_Release(event);
736 static void transform_release_sample(struct sample *sample)
738 list_remove(&sample->entry);
739 if (sample->sample)
740 IMFSample_Release(sample->sample);
741 heap_free(sample);
744 static void transform_stream_drop_samples(struct transform_stream *stream)
746 struct sample *sample, *sample2;
748 LIST_FOR_EACH_ENTRY_SAFE(sample, sample2, &stream->samples, struct sample, entry)
749 transform_release_sample(sample);
752 static void release_topo_node(struct topo_node *node)
754 unsigned int i;
756 switch (node->type)
758 case MF_TOPOLOGY_SOURCESTREAM_NODE:
759 if (node->u.source.source)
760 IMFMediaSource_Release(node->u.source.source);
761 break;
762 case MF_TOPOLOGY_TRANSFORM_NODE:
763 for (i = 0; i < node->u.transform.input_count; ++i)
764 transform_stream_drop_samples(&node->u.transform.inputs[i]);
765 for (i = 0; i < node->u.transform.output_count; ++i)
766 transform_stream_drop_samples(&node->u.transform.outputs[i]);
767 heap_free(node->u.transform.inputs);
768 heap_free(node->u.transform.outputs);
769 heap_free(node->u.transform.input_map);
770 heap_free(node->u.transform.output_map);
771 break;
772 case MF_TOPOLOGY_OUTPUT_NODE:
773 if (node->u.sink.allocator)
774 IMFVideoSampleAllocator_Release(node->u.sink.allocator);
775 if (node->u.sink.allocator_cb)
777 IMFVideoSampleAllocatorCallback_SetCallback(node->u.sink.allocator_cb, NULL);
778 IMFVideoSampleAllocatorCallback_Release(node->u.sink.allocator_cb);
780 break;
781 default:
785 if (node->object.object)
786 IUnknown_Release(node->object.object);
787 if (node->node)
788 IMFTopologyNode_Release(node->node);
789 heap_free(node);
792 static void session_shutdown_current_topology(struct media_session *session)
794 unsigned int shutdown, force_shutdown;
795 MF_TOPOLOGY_TYPE node_type;
796 IMFStreamSink *stream_sink;
797 IMFTopology *topology;
798 IMFTopologyNode *node;
799 IMFActivate *activate;
800 IMFMediaSink *sink;
801 WORD idx = 0;
802 HRESULT hr;
804 topology = session->presentation.current_topology;
805 force_shutdown = session->state == SESSION_STATE_SHUT_DOWN;
807 /* FIXME: should handle async MFTs, but these are not supported by the rest of the pipeline currently. */
809 while (SUCCEEDED(IMFTopology_GetNode(topology, idx++, &node)))
811 if (SUCCEEDED(IMFTopologyNode_GetNodeType(node, &node_type)) &&
812 node_type == MF_TOPOLOGY_OUTPUT_NODE)
814 shutdown = 1;
815 IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, &shutdown);
817 if (force_shutdown || shutdown)
819 if (SUCCEEDED(IMFTopologyNode_GetUnknown(node, &_MF_TOPONODE_IMFActivate, &IID_IMFActivate,
820 (void **)&activate)))
822 if (FAILED(hr = IMFActivate_ShutdownObject(activate)))
823 WARN("Failed to shut down activation object for the sink, hr %#x.\n", hr);
824 IMFActivate_Release(activate);
826 else if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink)))
828 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink)))
830 IMFMediaSink_Shutdown(sink);
831 IMFMediaSink_Release(sink);
834 IMFStreamSink_Release(stream_sink);
839 IMFTopologyNode_Release(node);
843 static void session_clear_presentation(struct media_session *session)
845 struct media_source *source, *source2;
846 struct media_sink *sink, *sink2;
847 struct topo_node *node, *node2;
848 struct session_op *op, *op2;
850 session_shutdown_current_topology(session);
852 IMFTopology_Clear(session->presentation.current_topology);
853 session->presentation.topo_status = MF_TOPOSTATUS_INVALID;
855 LIST_FOR_EACH_ENTRY_SAFE(source, source2, &session->presentation.sources, struct media_source, entry)
857 list_remove(&source->entry);
858 if (source->source)
859 IMFMediaSource_Release(source->source);
860 if (source->pd)
861 IMFPresentationDescriptor_Release(source->pd);
862 heap_free(source);
865 LIST_FOR_EACH_ENTRY_SAFE(node, node2, &session->presentation.nodes, struct topo_node, entry)
867 list_remove(&node->entry);
868 release_topo_node(node);
871 LIST_FOR_EACH_ENTRY_SAFE(sink, sink2, &session->presentation.sinks, struct media_sink, entry)
873 list_remove(&sink->entry);
875 if (sink->sink)
876 IMFMediaSink_Release(sink->sink);
877 if (sink->preroll)
878 IMFMediaSinkPreroll_Release(sink->preroll);
879 if (sink->event_generator)
880 IMFMediaEventGenerator_Release(sink->event_generator);
881 heap_free(sink);
884 LIST_FOR_EACH_ENTRY_SAFE(op, op2, &session->commands, struct session_op, entry)
886 list_remove(&op->entry);
887 IUnknown_Release(&op->IUnknown_iface);
891 static struct topo_node *session_get_node_by_id(const struct media_session *session, TOPOID id)
893 struct topo_node *node;
895 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
897 if (node->node_id == id)
898 return node;
901 return NULL;
904 static void session_start(struct media_session *session, const GUID *time_format, const PROPVARIANT *start_position)
906 struct media_source *source;
907 HRESULT hr;
909 switch (session->state)
911 case SESSION_STATE_STOPPED:
912 case SESSION_STATE_PAUSED:
914 session->presentation.time_format = *time_format;
915 session->presentation.start_position.vt = VT_EMPTY;
916 PropVariantCopy(&session->presentation.start_position, start_position);
918 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
920 if (!(session->presentation.flags & SESSION_FLAG_SOURCES_SUBSCRIBED))
922 if (FAILED(hr = IMFMediaSource_BeginGetEvent(source->source, &session->events_callback,
923 (IUnknown *)source->source)))
925 WARN("Failed to subscribe to source events, hr %#x.\n", hr);
929 if (FAILED(hr = IMFMediaSource_Start(source->source, source->pd, &GUID_NULL, start_position)))
930 WARN("Failed to start media source %p, hr %#x.\n", source->source, hr);
933 session->presentation.flags |= SESSION_FLAG_SOURCES_SUBSCRIBED;
934 session->state = SESSION_STATE_STARTING_SOURCES;
935 break;
936 case SESSION_STATE_STARTED:
937 FIXME("Seeking is not implemented.\n");
938 break;
939 case SESSION_STATE_CLOSED:
940 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStarted, &GUID_NULL,
941 MF_E_INVALIDREQUEST, NULL);
942 break;
943 default:
948 static void session_command_complete(struct media_session *session)
950 struct session_op *op;
951 struct list *e;
953 /* Pop current command, submit next. */
954 if ((e = list_head(&session->commands)))
956 op = LIST_ENTRY(e, struct session_op, entry);
957 list_remove(&op->entry);
958 IUnknown_Release(&op->IUnknown_iface);
961 if ((e = list_head(&session->commands)))
963 op = LIST_ENTRY(e, struct session_op, entry);
964 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface);
968 static void session_set_started(struct media_session *session)
970 struct media_source *source;
971 unsigned int caps, flags;
972 IMFMediaEvent *event;
974 session->state = SESSION_STATE_STARTED;
976 caps = session->caps | MFSESSIONCAP_PAUSE;
978 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
980 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source->source, &flags)))
982 if (!(flags & MFMEDIASOURCE_CAN_PAUSE))
984 caps &= ~MFSESSIONCAP_PAUSE;
985 break;
990 session_set_caps(session, caps);
992 if (SUCCEEDED(MFCreateMediaEvent(MESessionStarted, &GUID_NULL, S_OK, NULL, &event)))
994 IMFMediaEvent_SetUINT64(event, &MF_EVENT_PRESENTATION_TIME_OFFSET, 0);
995 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
996 IMFMediaEvent_Release(event);
998 session_command_complete(session);
1001 static void session_set_paused(struct media_session *session, HRESULT status)
1003 session->state = SESSION_STATE_PAUSED;
1004 if (SUCCEEDED(status))
1005 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
1006 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionPaused, &GUID_NULL, status, NULL);
1007 session_command_complete(session);
1010 static void session_set_closed(struct media_session *session, HRESULT status)
1012 session->state = SESSION_STATE_CLOSED;
1013 if (SUCCEEDED(status))
1014 session_set_caps(session, session->caps & ~(MFSESSIONCAP_START | MFSESSIONCAP_SEEK));
1015 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionClosed, &GUID_NULL, status, NULL);
1016 session_command_complete(session);
1019 static void session_pause(struct media_session *session)
1021 HRESULT hr;
1023 switch (session->state)
1025 case SESSION_STATE_STARTED:
1027 /* Transition in two steps - pause the clock, wait for sinks, then pause sources. */
1028 if (SUCCEEDED(hr = IMFPresentationClock_Pause(session->clock)))
1029 session->state = SESSION_STATE_PAUSING_SINKS;
1031 break;
1032 default:
1033 hr = MF_E_INVALIDREQUEST;
1036 if (FAILED(hr))
1037 session_set_paused(session, hr);
1040 static void session_set_stopped(struct media_session *session, HRESULT status)
1042 MediaEventType event_type;
1043 IMFMediaEvent *event;
1045 session->state = SESSION_STATE_STOPPED;
1046 event_type = session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION ? MESessionEnded : MESessionStopped;
1048 if (SUCCEEDED(MFCreateMediaEvent(event_type, &GUID_NULL, status, NULL, &event)))
1050 IMFMediaEvent_SetUINT64(event, &MF_SESSION_APPROX_EVENT_OCCURRENCE_TIME, session->presentation.clock_stop_time);
1051 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
1052 IMFMediaEvent_Release(event);
1054 session_command_complete(session);
1057 static void session_stop(struct media_session *session)
1059 HRESULT hr = MF_E_INVALIDREQUEST;
1061 switch (session->state)
1063 case SESSION_STATE_STARTED:
1064 case SESSION_STATE_PAUSED:
1066 /* Transition in two steps - stop the clock, wait for sinks, then stop sources. */
1067 IMFPresentationClock_GetTime(session->clock, &session->presentation.clock_stop_time);
1068 if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock)))
1069 session->state = SESSION_STATE_STOPPING_SINKS;
1070 else
1071 session_set_stopped(session, hr);
1073 break;
1074 case SESSION_STATE_STOPPED:
1075 hr = S_OK;
1076 /* fallthrough */
1077 default:
1078 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStopped, &GUID_NULL, hr, NULL);
1079 session_command_complete(session);
1080 break;
1084 static HRESULT session_finalize_sinks(struct media_session *session)
1086 IMFFinalizableMediaSink *fin_sink;
1087 BOOL sinks_finalized = TRUE;
1088 struct media_sink *sink;
1089 HRESULT hr = S_OK;
1091 session->presentation.flags &= ~SESSION_FLAG_FINALIZE_SINKS;
1092 session->state = SESSION_STATE_FINALIZING_SINKS;
1094 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
1096 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink->sink, &IID_IMFFinalizableMediaSink, (void **)&fin_sink)))
1098 hr = IMFFinalizableMediaSink_BeginFinalize(fin_sink, &session->sink_finalizer_callback,
1099 (IUnknown *)fin_sink);
1100 IMFFinalizableMediaSink_Release(fin_sink);
1101 if (FAILED(hr))
1102 break;
1103 sinks_finalized = FALSE;
1105 else
1106 sink->finalized = TRUE;
1109 if (sinks_finalized)
1110 session_set_closed(session, hr);
1112 return hr;
1115 static void session_close(struct media_session *session)
1117 HRESULT hr = S_OK;
1119 switch (session->state)
1121 case SESSION_STATE_STOPPED:
1122 hr = session_finalize_sinks(session);
1123 break;
1124 case SESSION_STATE_STARTED:
1125 case SESSION_STATE_PAUSED:
1126 session->presentation.flags |= SESSION_FLAG_FINALIZE_SINKS;
1127 if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock)))
1128 session->state = SESSION_STATE_STOPPING_SINKS;
1129 break;
1130 default:
1131 hr = MF_E_INVALIDREQUEST;
1132 break;
1135 if (FAILED(hr))
1136 session_set_closed(session, hr);
1139 static struct media_source *session_get_media_source(struct media_session *session, IMFMediaSource *source)
1141 struct media_source *cur;
1143 LIST_FOR_EACH_ENTRY(cur, &session->presentation.sources, struct media_source, entry)
1145 if (source == cur->source)
1146 return cur;
1149 return NULL;
1152 static void session_release_media_source(struct media_source *source)
1154 IMFMediaSource_Release(source->source);
1155 if (source->pd)
1156 IMFPresentationDescriptor_Release(source->pd);
1157 heap_free(source);
1160 static HRESULT session_add_media_source(struct media_session *session, IMFTopologyNode *node, IMFMediaSource *source)
1162 struct media_source *media_source;
1163 HRESULT hr;
1165 if (session_get_media_source(session, source))
1166 return S_FALSE;
1168 if (!(media_source = heap_alloc_zero(sizeof(*media_source))))
1169 return E_OUTOFMEMORY;
1171 media_source->source = source;
1172 IMFMediaSource_AddRef(media_source->source);
1174 hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, &IID_IMFPresentationDescriptor,
1175 (void **)&media_source->pd);
1177 if (SUCCEEDED(hr))
1178 list_add_tail(&session->presentation.sources, &media_source->entry);
1179 else
1180 session_release_media_source(media_source);
1182 return hr;
1185 static void session_raise_topology_set(struct media_session *session, IMFTopology *topology, HRESULT status)
1187 PROPVARIANT param;
1189 param.vt = topology ? VT_UNKNOWN : VT_EMPTY;
1190 param.punkVal = (IUnknown *)topology;
1192 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologySet, &GUID_NULL, status, &param);
1195 static DWORD session_get_object_rate_caps(IUnknown *object)
1197 IMFRateSupport *rate_support;
1198 DWORD caps = 0;
1199 float rate;
1201 if (SUCCEEDED(MFGetService(object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support)))
1203 rate = 0.0f;
1204 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support, MFRATE_FORWARD, TRUE, &rate)) && rate != 0.0f)
1205 caps |= MFSESSIONCAP_RATE_FORWARD;
1207 rate = 0.0f;
1208 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support, MFRATE_REVERSE, TRUE, &rate)) && rate != 0.0f)
1209 caps |= MFSESSIONCAP_RATE_REVERSE;
1211 IMFRateSupport_Release(rate_support);
1214 return caps;
1217 static HRESULT session_add_media_sink(struct media_session *session, IMFTopologyNode *node, IMFMediaSink *sink)
1219 struct media_sink *media_sink;
1220 DWORD flags;
1222 LIST_FOR_EACH_ENTRY(media_sink, &session->presentation.sinks, struct media_sink, entry)
1224 if (sink == media_sink->sink)
1225 return S_FALSE;
1228 if (!(media_sink = heap_alloc_zero(sizeof(*media_sink))))
1229 return E_OUTOFMEMORY;
1231 media_sink->sink = sink;
1232 IMFMediaSink_AddRef(media_sink->sink);
1234 IMFMediaSink_QueryInterface(media_sink->sink, &IID_IMFMediaEventGenerator, (void **)&media_sink->event_generator);
1236 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink, &flags)) && flags & MEDIASINK_CAN_PREROLL)
1238 if (SUCCEEDED(IMFMediaSink_QueryInterface(media_sink->sink, &IID_IMFMediaSinkPreroll, (void **)&media_sink->preroll)))
1239 session->presentation.flags |= SESSION_FLAG_NEEDS_PREROLL;
1242 list_add_tail(&session->presentation.sinks, &media_sink->entry);
1244 return S_OK;
1247 static HRESULT session_set_transform_stream_info(struct topo_node *node)
1249 unsigned int *input_map = NULL, *output_map = NULL;
1250 unsigned int i, input_count, output_count;
1251 struct transform_stream *streams;
1252 HRESULT hr;
1254 hr = IMFTransform_GetStreamCount(node->object.transform, &input_count, &output_count);
1255 if (SUCCEEDED(hr) && (input_count > 1 || output_count > 1))
1257 input_map = heap_calloc(input_count, sizeof(*input_map));
1258 output_map = heap_calloc(output_count, sizeof(*output_map));
1259 if (FAILED(IMFTransform_GetStreamIDs(node->object.transform, input_count, input_map,
1260 output_count, output_map)))
1262 /* Assume sequential identifiers. */
1263 heap_free(input_map);
1264 heap_free(output_map);
1265 input_map = output_map = NULL;
1269 if (SUCCEEDED(hr))
1271 streams = heap_calloc(input_count, sizeof(*streams));
1272 for (i = 0; i < input_count; ++i)
1273 list_init(&streams[i].samples);
1274 node->u.transform.inputs = streams;
1276 streams = heap_calloc(output_count, sizeof(*streams));
1277 for (i = 0; i < output_count; ++i)
1278 list_init(&streams[i].samples);
1279 node->u.transform.outputs = streams;
1281 node->u.transform.input_count = input_count;
1282 node->u.transform.output_count = output_count;
1283 node->u.transform.input_map = input_map;
1284 node->u.transform.output_map = output_map;
1287 return hr;
1290 static HRESULT session_get_stream_sink_type(IMFStreamSink *sink, IMFMediaType **media_type)
1292 IMFMediaTypeHandler *handler;
1293 HRESULT hr;
1295 if (SUCCEEDED(hr = IMFStreamSink_GetMediaTypeHandler(sink, &handler)))
1297 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, media_type);
1298 IMFMediaTypeHandler_Release(handler);
1301 return hr;
1304 static HRESULT WINAPI node_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify *iface,
1305 REFIID riid, void **obj)
1307 if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorNotify) ||
1308 IsEqualIID(riid, &IID_IUnknown))
1310 *obj = iface;
1311 IMFVideoSampleAllocatorNotify_AddRef(iface);
1312 return S_OK;
1315 *obj = NULL;
1316 return E_NOINTERFACE;
1319 static ULONG WINAPI node_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify *iface)
1321 return 2;
1324 static ULONG WINAPI node_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify *iface)
1326 return 1;
1329 static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output);
1331 static HRESULT WINAPI node_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify *iface)
1333 struct topo_node *topo_node = impl_node_from_IMFVideoSampleAllocatorNotify(iface);
1334 struct session_op *op;
1336 if (SUCCEEDED(create_session_op(SESSION_CMD_SA_READY, &op)))
1338 op->u.sa_ready.node_id = topo_node->node_id;
1339 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &topo_node->session->commands_callback, &op->IUnknown_iface);
1340 IUnknown_Release(&op->IUnknown_iface);
1343 return S_OK;
1346 static const IMFVideoSampleAllocatorNotifyVtbl node_sample_allocator_cb_vtbl =
1348 node_sample_allocator_cb_QueryInterface,
1349 node_sample_allocator_cb_AddRef,
1350 node_sample_allocator_cb_Release,
1351 node_sample_allocator_cb_NotifyRelease,
1354 static HRESULT session_append_node(struct media_session *session, IMFTopologyNode *node)
1356 struct topo_node *topo_node;
1357 IMFMediaSink *media_sink;
1358 IMFMediaType *media_type;
1359 IMFStreamDescriptor *sd;
1360 HRESULT hr = S_OK;
1362 if (!(topo_node = heap_alloc_zero(sizeof(*topo_node))))
1363 return E_OUTOFMEMORY;
1365 IMFTopologyNode_GetNodeType(node, &topo_node->type);
1366 IMFTopologyNode_GetTopoNodeID(node, &topo_node->node_id);
1367 topo_node->node = node;
1368 IMFTopologyNode_AddRef(topo_node->node);
1369 topo_node->session = session;
1371 switch (topo_node->type)
1373 case MF_TOPOLOGY_OUTPUT_NODE:
1374 topo_node->u.sink.notify_cb.lpVtbl = &node_sample_allocator_cb_vtbl;
1376 if (FAILED(hr = topology_node_get_object(node, &IID_IMFStreamSink, (void **)&topo_node->object.object)))
1378 WARN("Failed to get stream sink interface, hr %#x.\n", hr);
1379 break;
1382 if (FAILED(hr = IMFStreamSink_GetMediaSink(topo_node->object.sink_stream, &media_sink)))
1383 break;
1385 if (SUCCEEDED(hr = session_add_media_sink(session, node, media_sink)))
1387 if (SUCCEEDED(session_get_stream_sink_type(topo_node->object.sink_stream, &media_type)))
1389 if (SUCCEEDED(MFGetService(topo_node->object.object, &MR_VIDEO_ACCELERATION_SERVICE,
1390 &IID_IMFVideoSampleAllocator, (void **)&topo_node->u.sink.allocator)))
1392 if (FAILED(hr = IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node->u.sink.allocator,
1393 2, media_type)))
1395 WARN("Failed to initialize sample allocator for the stream, hr %#x.\n", hr);
1397 IMFVideoSampleAllocator_QueryInterface(topo_node->u.sink.allocator,
1398 &IID_IMFVideoSampleAllocatorCallback, (void **)&topo_node->u.sink.allocator_cb);
1399 IMFVideoSampleAllocatorCallback_SetCallback(topo_node->u.sink.allocator_cb,
1400 &topo_node->u.sink.notify_cb);
1402 IMFMediaType_Release(media_type);
1405 IMFMediaSink_Release(media_sink);
1407 break;
1408 case MF_TOPOLOGY_SOURCESTREAM_NODE:
1409 if (FAILED(IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_SOURCE, &IID_IMFMediaSource,
1410 (void **)&topo_node->u.source.source)))
1412 WARN("Missing MF_TOPONODE_SOURCE, hr %#x.\n", hr);
1413 break;
1416 if (FAILED(hr = session_add_media_source(session, node, topo_node->u.source.source)))
1417 break;
1419 if (FAILED(hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR,
1420 &IID_IMFStreamDescriptor, (void **)&sd)))
1422 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#x.\n", hr);
1423 break;
1426 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &topo_node->u.source.stream_id);
1427 IMFStreamDescriptor_Release(sd);
1429 break;
1430 case MF_TOPOLOGY_TRANSFORM_NODE:
1432 if (SUCCEEDED(hr = topology_node_get_object(node, &IID_IMFTransform, (void **)&topo_node->object.transform)))
1434 hr = session_set_transform_stream_info(topo_node);
1436 else
1437 WARN("Failed to get IMFTransform for MFT node, hr %#x.\n", hr);
1439 break;
1440 case MF_TOPOLOGY_TEE_NODE:
1441 FIXME("Unsupported node type %d.\n", topo_node->type);
1443 break;
1444 default:
1448 if (SUCCEEDED(hr))
1449 list_add_tail(&session->presentation.nodes, &topo_node->entry);
1450 else
1451 release_topo_node(topo_node);
1453 return hr;
1456 static HRESULT session_collect_nodes(struct media_session *session)
1458 IMFTopology *topology = session->presentation.current_topology;
1459 IMFTopologyNode *node;
1460 WORD i, count = 0;
1461 HRESULT hr;
1463 if (!list_empty(&session->presentation.nodes))
1464 return S_OK;
1466 if (FAILED(hr = IMFTopology_GetNodeCount(topology, &count)))
1467 return hr;
1469 for (i = 0; i < count; ++i)
1471 if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
1473 WARN("Failed to get node %u.\n", i);
1474 break;
1477 hr = session_append_node(session, node);
1478 IMFTopologyNode_Release(node);
1479 if (FAILED(hr))
1481 WARN("Failed to add node %u.\n", i);
1482 break;
1486 return hr;
1489 static HRESULT session_set_current_topology(struct media_session *session, IMFTopology *topology)
1491 struct media_source *source;
1492 DWORD caps, object_flags;
1493 struct media_sink *sink;
1494 struct topo_node *node;
1495 struct session_op *op;
1496 IMFMediaEvent *event;
1497 HRESULT hr;
1499 if (session->quality_manager)
1501 if (SUCCEEDED(create_session_op(SESSION_CMD_QM_NOTIFY_TOPOLOGY, &op)))
1503 op->u.notify_topology.topology = topology;
1504 IMFTopology_AddRef(op->u.notify_topology.topology);
1505 session_submit_command(session, op);
1506 IUnknown_Release(&op->IUnknown_iface);
1510 if (FAILED(hr = IMFTopology_CloneFrom(session->presentation.current_topology, topology)))
1512 WARN("Failed to clone topology, hr %#x.\n", hr);
1513 return hr;
1516 session_collect_nodes(session);
1518 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
1520 if (node->type == MF_TOPOLOGY_TRANSFORM_NODE)
1522 if (FAILED(hr = IMFTransform_ProcessMessage(node->object.transform,
1523 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0)))
1524 return hr;
1528 /* FIXME: attributes are all zero for now */
1529 if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime, &GUID_NULL, S_OK, NULL, &event)))
1531 IMFMediaEvent_SetUINT64(event, &MF_EVENT_START_PRESENTATION_TIME, 0);
1532 IMFMediaEvent_SetUINT64(event, &MF_EVENT_PRESENTATION_TIME_OFFSET, 0);
1533 IMFMediaEvent_SetUINT64(event, &MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT, 0);
1535 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
1536 IMFMediaEvent_Release(event);
1539 /* Update session caps. */
1540 caps = MFSESSIONCAP_START | MFSESSIONCAP_SEEK | MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE |
1541 MFSESSIONCAP_DOES_NOT_USE_NETWORK;
1543 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
1545 if (!caps)
1546 break;
1548 object_flags = 0;
1549 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source->source, &object_flags)))
1551 if (!(object_flags & MFMEDIASOURCE_DOES_NOT_USE_NETWORK))
1552 caps &= ~MFSESSIONCAP_DOES_NOT_USE_NETWORK;
1553 if (!(object_flags & MFMEDIASOURCE_CAN_SEEK))
1554 caps &= ~MFSESSIONCAP_SEEK;
1557 /* Mask unsupported rate caps. */
1559 caps &= session_get_object_rate_caps((IUnknown *)source->source)
1560 | ~(MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE);
1563 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
1565 if (!caps)
1566 break;
1568 object_flags = 0;
1569 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink->sink, &object_flags)))
1571 if (!(object_flags & MEDIASINK_RATELESS))
1572 caps &= session_get_object_rate_caps((IUnknown *)sink->sink)
1573 | ~(MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE);
1577 session_set_caps(session, caps);
1579 return S_OK;
1582 static void session_set_topology(struct media_session *session, DWORD flags, IMFTopology *topology)
1584 IMFTopology *resolved_topology = NULL;
1585 HRESULT hr = S_OK;
1587 /* Resolve unless claimed to be full. */
1588 if (!(flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT) && topology)
1590 if (!(flags & MFSESSION_SETTOPOLOGY_NORESOLUTION))
1592 hr = session_bind_output_nodes(topology);
1594 if (SUCCEEDED(hr))
1595 hr = IMFTopoLoader_Load(session->topo_loader, topology, &resolved_topology, NULL /* FIXME? */);
1597 if (SUCCEEDED(hr))
1599 topology = resolved_topology;
1604 if (flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT)
1606 if ((topology && topology == session->presentation.current_topology) || !topology)
1608 /* FIXME: stop current topology, queue next one. */
1609 session_clear_presentation(session);
1611 else
1612 hr = S_FALSE;
1614 topology = NULL;
1616 else if (topology && flags & MFSESSION_SETTOPOLOGY_IMMEDIATE)
1618 session_clear_topologies(session);
1619 session_clear_presentation(session);
1622 session_raise_topology_set(session, topology, hr);
1624 /* With no current topology set it right away, otherwise queue. */
1625 if (topology)
1627 struct queued_topology *queued_topology;
1629 if ((queued_topology = heap_alloc_zero(sizeof(*queued_topology))))
1631 queued_topology->topology = topology;
1632 IMFTopology_AddRef(queued_topology->topology);
1634 list_add_tail(&session->topologies, &queued_topology->entry);
1637 if (session->presentation.topo_status == MF_TOPOSTATUS_INVALID)
1639 hr = session_set_current_topology(session, topology);
1640 session_set_topo_status(session, hr, MF_TOPOSTATUS_READY);
1644 if (resolved_topology)
1645 IMFTopology_Release(resolved_topology);
1648 static HRESULT WINAPI mfsession_QueryInterface(IMFMediaSession *iface, REFIID riid, void **out)
1650 struct media_session *session = impl_from_IMFMediaSession(iface);
1652 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1654 if (IsEqualIID(riid, &IID_IMFMediaSession) ||
1655 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
1656 IsEqualIID(riid, &IID_IUnknown))
1658 *out = &session->IMFMediaSession_iface;
1659 IMFMediaSession_AddRef(iface);
1660 return S_OK;
1662 else if (IsEqualIID(riid, &IID_IMFGetService))
1664 *out = &session->IMFGetService_iface;
1665 IMFMediaSession_AddRef(iface);
1666 return S_OK;
1669 WARN("Unsupported %s.\n", debugstr_guid(riid));
1670 *out = NULL;
1671 return E_NOINTERFACE;
1674 static ULONG WINAPI mfsession_AddRef(IMFMediaSession *iface)
1676 struct media_session *session = impl_from_IMFMediaSession(iface);
1677 ULONG refcount = InterlockedIncrement(&session->refcount);
1679 TRACE("%p, refcount %u.\n", iface, refcount);
1681 return refcount;
1684 static ULONG WINAPI mfsession_Release(IMFMediaSession *iface)
1686 struct media_session *session = impl_from_IMFMediaSession(iface);
1687 ULONG refcount = InterlockedDecrement(&session->refcount);
1689 TRACE("%p, refcount %u.\n", iface, refcount);
1691 if (!refcount)
1693 session_clear_topologies(session);
1694 session_clear_presentation(session);
1695 if (session->presentation.current_topology)
1696 IMFTopology_Release(session->presentation.current_topology);
1697 if (session->event_queue)
1698 IMFMediaEventQueue_Release(session->event_queue);
1699 if (session->clock)
1700 IMFPresentationClock_Release(session->clock);
1701 if (session->system_time_source)
1702 IMFPresentationTimeSource_Release(session->system_time_source);
1703 if (session->clock_rate_control)
1704 IMFRateControl_Release(session->clock_rate_control);
1705 if (session->topo_loader)
1706 IMFTopoLoader_Release(session->topo_loader);
1707 if (session->quality_manager)
1708 IMFQualityManager_Release(session->quality_manager);
1709 DeleteCriticalSection(&session->cs);
1710 heap_free(session);
1713 return refcount;
1716 static HRESULT WINAPI mfsession_GetEvent(IMFMediaSession *iface, DWORD flags, IMFMediaEvent **event)
1718 struct media_session *session = impl_from_IMFMediaSession(iface);
1720 TRACE("%p, %#x, %p.\n", iface, flags, event);
1722 return IMFMediaEventQueue_GetEvent(session->event_queue, flags, event);
1725 static HRESULT WINAPI mfsession_BeginGetEvent(IMFMediaSession *iface, IMFAsyncCallback *callback, IUnknown *state)
1727 struct media_session *session = impl_from_IMFMediaSession(iface);
1729 TRACE("%p, %p, %p.\n", iface, callback, state);
1731 return IMFMediaEventQueue_BeginGetEvent(session->event_queue, callback, state);
1734 static HRESULT WINAPI mfsession_EndGetEvent(IMFMediaSession *iface, IMFAsyncResult *result, IMFMediaEvent **event)
1736 struct media_session *session = impl_from_IMFMediaSession(iface);
1738 TRACE("%p, %p, %p.\n", iface, result, event);
1740 return IMFMediaEventQueue_EndGetEvent(session->event_queue, result, event);
1743 static HRESULT WINAPI mfsession_QueueEvent(IMFMediaSession *iface, MediaEventType event_type, REFGUID ext_type,
1744 HRESULT hr, const PROPVARIANT *value)
1746 struct media_session *session = impl_from_IMFMediaSession(iface);
1748 TRACE("%p, %d, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
1750 return IMFMediaEventQueue_QueueEventParamVar(session->event_queue, event_type, ext_type, hr, value);
1753 static HRESULT WINAPI mfsession_SetTopology(IMFMediaSession *iface, DWORD flags, IMFTopology *topology)
1755 struct media_session *session = impl_from_IMFMediaSession(iface);
1756 struct session_op *op;
1757 WORD node_count = 0;
1758 HRESULT hr;
1760 TRACE("%p, %#x, %p.\n", iface, flags, topology);
1762 if (topology)
1764 if (FAILED(IMFTopology_GetNodeCount(topology, &node_count)) || node_count == 0)
1765 return E_INVALIDARG;
1768 if (FAILED(hr = create_session_op(SESSION_CMD_SET_TOPOLOGY, &op)))
1769 return hr;
1771 op->u.set_topology.flags = flags;
1772 op->u.set_topology.topology = topology;
1773 if (op->u.set_topology.topology)
1774 IMFTopology_AddRef(op->u.set_topology.topology);
1776 hr = session_submit_command(session, op);
1777 IUnknown_Release(&op->IUnknown_iface);
1779 return hr;
1782 static HRESULT WINAPI mfsession_ClearTopologies(IMFMediaSession *iface)
1784 struct media_session *session = impl_from_IMFMediaSession(iface);
1786 TRACE("%p.\n", iface);
1788 return session_submit_simple_command(session, SESSION_CMD_CLEAR_TOPOLOGIES);
1791 static HRESULT WINAPI mfsession_Start(IMFMediaSession *iface, const GUID *format, const PROPVARIANT *start_position)
1793 struct media_session *session = impl_from_IMFMediaSession(iface);
1794 struct session_op *op;
1795 HRESULT hr;
1797 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), start_position);
1799 if (!start_position)
1800 return E_POINTER;
1802 if (FAILED(hr = create_session_op(SESSION_CMD_START, &op)))
1803 return hr;
1805 op->u.start.time_format = format ? *format : GUID_NULL;
1806 hr = PropVariantCopy(&op->u.start.start_position, start_position);
1808 if (SUCCEEDED(hr))
1809 hr = session_submit_command(session, op);
1811 IUnknown_Release(&op->IUnknown_iface);
1813 return hr;
1816 static HRESULT WINAPI mfsession_Pause(IMFMediaSession *iface)
1818 struct media_session *session = impl_from_IMFMediaSession(iface);
1820 TRACE("%p.\n", iface);
1822 return session_submit_simple_command(session, SESSION_CMD_PAUSE);
1825 static HRESULT WINAPI mfsession_Stop(IMFMediaSession *iface)
1827 struct media_session *session = impl_from_IMFMediaSession(iface);
1829 TRACE("%p.\n", iface);
1831 return session_submit_simple_command(session, SESSION_CMD_STOP);
1834 static HRESULT WINAPI mfsession_Close(IMFMediaSession *iface)
1836 struct media_session *session = impl_from_IMFMediaSession(iface);
1838 TRACE("%p.\n", iface);
1840 return session_submit_simple_command(session, SESSION_CMD_CLOSE);
1843 static HRESULT WINAPI mfsession_Shutdown(IMFMediaSession *iface)
1845 struct media_session *session = impl_from_IMFMediaSession(iface);
1846 HRESULT hr = S_OK;
1848 TRACE("%p.\n", iface);
1850 EnterCriticalSection(&session->cs);
1851 if (SUCCEEDED(hr = session_is_shut_down(session)))
1853 session->state = SESSION_STATE_SHUT_DOWN;
1854 IMFMediaEventQueue_Shutdown(session->event_queue);
1855 if (session->quality_manager)
1856 IMFQualityManager_Shutdown(session->quality_manager);
1857 MFShutdownObject((IUnknown *)session->clock);
1858 IMFPresentationClock_Release(session->clock);
1859 session->clock = NULL;
1860 session_clear_presentation(session);
1862 LeaveCriticalSection(&session->cs);
1864 return hr;
1867 static HRESULT WINAPI mfsession_GetClock(IMFMediaSession *iface, IMFClock **clock)
1869 struct media_session *session = impl_from_IMFMediaSession(iface);
1870 HRESULT hr;
1872 TRACE("%p, %p.\n", iface, clock);
1874 EnterCriticalSection(&session->cs);
1875 if (SUCCEEDED(hr = session_is_shut_down(session)))
1877 *clock = (IMFClock *)session->clock;
1878 IMFClock_AddRef(*clock);
1880 LeaveCriticalSection(&session->cs);
1882 return hr;
1885 static HRESULT WINAPI mfsession_GetSessionCapabilities(IMFMediaSession *iface, DWORD *caps)
1887 struct media_session *session = impl_from_IMFMediaSession(iface);
1888 HRESULT hr = S_OK;
1890 TRACE("%p, %p.\n", iface, caps);
1892 if (!caps)
1893 return E_POINTER;
1895 EnterCriticalSection(&session->cs);
1896 if (SUCCEEDED(hr = session_is_shut_down(session)))
1897 *caps = session->caps;
1898 LeaveCriticalSection(&session->cs);
1900 return hr;
1903 static HRESULT WINAPI mfsession_GetFullTopology(IMFMediaSession *iface, DWORD flags, TOPOID id, IMFTopology **topology)
1905 struct media_session *session = impl_from_IMFMediaSession(iface);
1906 struct queued_topology *queued;
1907 TOPOID topo_id;
1908 HRESULT hr;
1910 TRACE("%p, %#x, %s, %p.\n", iface, flags, wine_dbgstr_longlong(id), topology);
1912 *topology = NULL;
1914 EnterCriticalSection(&session->cs);
1916 if (SUCCEEDED(hr = session_is_shut_down(session)))
1918 if (flags & MFSESSION_GETFULLTOPOLOGY_CURRENT)
1920 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
1921 *topology = session->presentation.current_topology;
1922 else
1923 hr = MF_E_INVALIDREQUEST;
1925 else
1927 LIST_FOR_EACH_ENTRY(queued, &session->topologies, struct queued_topology, entry)
1929 if (SUCCEEDED(IMFTopology_GetTopologyID(queued->topology, &topo_id)) && topo_id == id)
1931 *topology = queued->topology;
1932 break;
1937 if (*topology)
1938 IMFTopology_AddRef(*topology);
1941 LeaveCriticalSection(&session->cs);
1943 return hr;
1946 static const IMFMediaSessionVtbl mfmediasessionvtbl =
1948 mfsession_QueryInterface,
1949 mfsession_AddRef,
1950 mfsession_Release,
1951 mfsession_GetEvent,
1952 mfsession_BeginGetEvent,
1953 mfsession_EndGetEvent,
1954 mfsession_QueueEvent,
1955 mfsession_SetTopology,
1956 mfsession_ClearTopologies,
1957 mfsession_Start,
1958 mfsession_Pause,
1959 mfsession_Stop,
1960 mfsession_Close,
1961 mfsession_Shutdown,
1962 mfsession_GetClock,
1963 mfsession_GetSessionCapabilities,
1964 mfsession_GetFullTopology,
1967 static HRESULT WINAPI session_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1969 struct media_session *session = impl_from_IMFGetService(iface);
1970 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
1973 static ULONG WINAPI session_get_service_AddRef(IMFGetService *iface)
1975 struct media_session *session = impl_from_IMFGetService(iface);
1976 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
1979 static ULONG WINAPI session_get_service_Release(IMFGetService *iface)
1981 struct media_session *session = impl_from_IMFGetService(iface);
1982 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
1985 static HRESULT WINAPI session_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
1987 struct media_session *session = impl_from_IMFGetService(iface);
1989 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1991 *obj = NULL;
1993 if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE))
1995 if (IsEqualIID(riid, &IID_IMFRateSupport))
1997 *obj = &session->IMFRateSupport_iface;
1999 else if (IsEqualIID(riid, &IID_IMFRateControl))
2001 *obj = &session->IMFRateControl_iface;
2004 else if (IsEqualGUID(service, &MF_LOCAL_MFT_REGISTRATION_SERVICE))
2006 return IMFLocalMFTRegistration_QueryInterface(&local_mft_registration, riid, obj);
2008 else if (IsEqualGUID(service, &MF_TOPONODE_ATTRIBUTE_EDITOR_SERVICE))
2010 *obj = &session->IMFTopologyNodeAttributeEditor_iface;
2012 else if (IsEqualGUID(service, &MR_VIDEO_RENDER_SERVICE))
2014 IMFStreamSink *stream_sink;
2015 IMFTopologyNode *node;
2016 IMFCollection *nodes;
2017 IMFMediaSink *sink;
2018 unsigned int i = 0;
2019 IUnknown *vr;
2020 HRESULT hr;
2022 EnterCriticalSection(&session->cs);
2024 /* Use first sink to support IMFVideoRenderer. */
2025 if (session->presentation.current_topology)
2027 if (SUCCEEDED(IMFTopology_GetOutputNodeCollection(session->presentation.current_topology,
2028 &nodes)))
2030 while (IMFCollection_GetElement(nodes, i++, (IUnknown **)&node) == S_OK)
2032 if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink)))
2034 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink)))
2036 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink, &IID_IMFVideoRenderer, (void **)&vr)))
2038 if (FAILED(hr = MFGetService(vr, service, riid, obj)))
2039 WARN("Failed to get service from video renderer %#x.\n", hr);
2040 IUnknown_Release(vr);
2043 IMFStreamSink_Release(stream_sink);
2046 IMFTopologyNode_Release(node);
2048 if (*obj)
2049 break;
2052 IMFCollection_Release(nodes);
2056 LeaveCriticalSection(&session->cs);
2058 else
2059 FIXME("Unsupported service %s.\n", debugstr_guid(service));
2061 if (*obj)
2062 IUnknown_AddRef((IUnknown *)*obj);
2064 return *obj ? S_OK : E_NOINTERFACE;
2067 static const IMFGetServiceVtbl session_get_service_vtbl =
2069 session_get_service_QueryInterface,
2070 session_get_service_AddRef,
2071 session_get_service_Release,
2072 session_get_service_GetService,
2075 static HRESULT WINAPI session_commands_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
2077 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
2078 IsEqualIID(riid, &IID_IUnknown))
2080 *obj = iface;
2081 IMFAsyncCallback_AddRef(iface);
2082 return S_OK;
2085 WARN("Unsupported %s.\n", debugstr_guid(riid));
2086 *obj = NULL;
2087 return E_NOINTERFACE;
2090 static ULONG WINAPI session_commands_callback_AddRef(IMFAsyncCallback *iface)
2092 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2093 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2096 static ULONG WINAPI session_commands_callback_Release(IMFAsyncCallback *iface)
2098 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2099 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2102 static HRESULT WINAPI session_commands_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
2104 return E_NOTIMPL;
2107 static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
2109 struct session_op *op = impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result));
2110 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2111 struct topo_node *topo_node;
2112 IMFTopologyNode *upstream_node;
2113 unsigned int upstream_output;
2115 EnterCriticalSection(&session->cs);
2117 switch (op->command)
2119 case SESSION_CMD_CLEAR_TOPOLOGIES:
2120 session_clear_topologies(session);
2121 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologiesCleared, &GUID_NULL,
2122 S_OK, NULL);
2123 session_command_complete(session);
2124 break;
2125 case SESSION_CMD_SET_TOPOLOGY:
2126 session_set_topology(session, op->u.set_topology.flags, op->u.set_topology.topology);
2127 session_command_complete(session);
2128 break;
2129 case SESSION_CMD_START:
2130 session_start(session, &op->u.start.time_format, &op->u.start.start_position);
2131 break;
2132 case SESSION_CMD_PAUSE:
2133 session_pause(session);
2134 break;
2135 case SESSION_CMD_STOP:
2136 session_stop(session);
2137 break;
2138 case SESSION_CMD_CLOSE:
2139 session_close(session);
2140 break;
2141 case SESSION_CMD_QM_NOTIFY_TOPOLOGY:
2142 IMFQualityManager_NotifyTopology(session->quality_manager, op->u.notify_topology.topology);
2143 session_command_complete(session);
2144 break;
2145 case SESSION_CMD_SA_READY:
2146 topo_node = session_get_node_by_id(session, op->u.sa_ready.node_id);
2148 if (topo_node->u.sink.requests)
2150 if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node->node, 0, &upstream_node, &upstream_output)))
2152 session_request_sample_from_node(session, upstream_node, upstream_output);
2153 IMFTopologyNode_Release(upstream_node);
2156 break;
2157 default:
2161 LeaveCriticalSection(&session->cs);
2163 return S_OK;
2166 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl =
2168 session_commands_callback_QueryInterface,
2169 session_commands_callback_AddRef,
2170 session_commands_callback_Release,
2171 session_commands_callback_GetParameters,
2172 session_commands_callback_Invoke,
2175 static HRESULT WINAPI session_events_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
2177 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
2178 IsEqualIID(riid, &IID_IUnknown))
2180 *obj = iface;
2181 IMFAsyncCallback_AddRef(iface);
2182 return S_OK;
2185 WARN("Unsupported %s.\n", debugstr_guid(riid));
2186 *obj = NULL;
2187 return E_NOINTERFACE;
2190 static ULONG WINAPI session_events_callback_AddRef(IMFAsyncCallback *iface)
2192 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
2193 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2196 static ULONG WINAPI session_events_callback_Release(IMFAsyncCallback *iface)
2198 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
2199 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2202 static HRESULT WINAPI session_events_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
2204 return E_NOTIMPL;
2207 static HRESULT session_add_media_stream(struct media_session *session, IMFMediaSource *source, IMFMediaStream *stream)
2209 struct topo_node *node;
2210 IMFStreamDescriptor *sd;
2211 DWORD stream_id = 0;
2212 HRESULT hr;
2214 if (FAILED(hr = IMFMediaStream_GetStreamDescriptor(stream, &sd)))
2215 return hr;
2217 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &stream_id);
2218 IMFStreamDescriptor_Release(sd);
2219 if (FAILED(hr))
2220 return hr;
2222 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2224 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->u.source.source == source
2225 && node->u.source.stream_id == stream_id)
2227 if (node->object.source_stream)
2229 WARN("Node already has stream set.\n");
2230 return S_FALSE;
2233 node->object.source_stream = stream;
2234 IMFMediaStream_AddRef(node->object.source_stream);
2235 break;
2239 return S_OK;
2242 static BOOL session_is_source_nodes_state(struct media_session *session, enum object_state state)
2244 struct media_source *source;
2245 struct topo_node *node;
2247 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2249 if (source->state != state)
2250 return FALSE;
2253 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2255 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->state != state)
2256 return FALSE;
2259 return TRUE;
2262 static BOOL session_is_output_nodes_state(struct media_session *session, enum object_state state)
2264 struct topo_node *node;
2266 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2268 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->state != state)
2269 return FALSE;
2272 return TRUE;
2275 static enum object_state session_get_object_state_for_event(MediaEventType event)
2277 switch (event)
2279 case MESourceStarted:
2280 case MEStreamStarted:
2281 case MEStreamSinkStarted:
2282 return OBJ_STATE_STARTED;
2283 case MESourcePaused:
2284 case MEStreamPaused:
2285 case MEStreamSinkPaused:
2286 return OBJ_STATE_PAUSED;
2287 case MESourceStopped:
2288 case MEStreamStopped:
2289 case MEStreamSinkStopped:
2290 return OBJ_STATE_STOPPED;
2291 case MEStreamSinkPrerolled:
2292 return OBJ_STATE_PREROLLED;
2293 default:
2294 return OBJ_STATE_INVALID;
2298 static void session_set_consumed_clock(IUnknown *object, IMFPresentationClock *clock)
2300 IMFClockConsumer *consumer;
2302 if (SUCCEEDED(IUnknown_QueryInterface(object, &IID_IMFClockConsumer, (void **)&consumer)))
2304 IMFClockConsumer_SetPresentationClock(consumer, clock);
2305 IMFClockConsumer_Release(consumer);
2309 static void session_set_presentation_clock(struct media_session *session)
2311 IMFPresentationTimeSource *time_source = NULL;
2312 struct media_source *source;
2313 struct media_sink *sink;
2314 struct topo_node *node;
2315 HRESULT hr;
2317 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2319 if (node->type == MF_TOPOLOGY_TRANSFORM_NODE)
2320 IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
2323 if (!(session->presentation.flags & SESSION_FLAG_PRESENTATION_CLOCK_SET))
2325 /* Attempt to get time source from the sinks. */
2326 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2328 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink->sink, &IID_IMFPresentationTimeSource,
2329 (void **)&time_source)))
2330 break;
2333 if (time_source)
2335 hr = IMFPresentationClock_SetTimeSource(session->clock, time_source);
2336 IMFPresentationTimeSource_Release(time_source);
2338 else
2339 hr = IMFPresentationClock_SetTimeSource(session->clock, session->system_time_source);
2341 if (FAILED(hr))
2342 WARN("Failed to set time source, hr %#x.\n", hr);
2344 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2346 if (node->type != MF_TOPOLOGY_OUTPUT_NODE)
2347 continue;
2349 if (FAILED(hr = IMFStreamSink_BeginGetEvent(node->object.sink_stream, &session->events_callback,
2350 node->object.object)))
2352 WARN("Failed to subscribe to stream sink events, hr %#x.\n", hr);
2356 /* Set clock for all topology nodes. */
2357 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2359 session_set_consumed_clock((IUnknown *)source->source, session->clock);
2362 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2364 if (sink->event_generator && FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(sink->event_generator,
2365 &session->events_callback, (IUnknown *)sink->event_generator)))
2367 WARN("Failed to subscribe to sink events, hr %#x.\n", hr);
2370 if (FAILED(hr = IMFMediaSink_SetPresentationClock(sink->sink, session->clock)))
2371 WARN("Failed to set presentation clock for the sink, hr %#x.\n", hr);
2374 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2376 if (node->type != MF_TOPOLOGY_TRANSFORM_NODE)
2377 continue;
2379 session_set_consumed_clock(node->object.object, session->clock);
2382 session->presentation.flags |= SESSION_FLAG_PRESENTATION_CLOCK_SET;
2386 static HRESULT session_start_clock(struct media_session *session)
2388 LONGLONG start_offset = 0;
2389 HRESULT hr;
2391 if (IsEqualGUID(&session->presentation.time_format, &GUID_NULL))
2393 if (session->presentation.start_position.vt == VT_EMPTY)
2394 start_offset = PRESENTATION_CURRENT_POSITION;
2395 else if (session->presentation.start_position.vt == VT_I8)
2396 start_offset = session->presentation.start_position.hVal.QuadPart;
2397 else
2398 FIXME("Unhandled position type %d.\n", session->presentation.start_position.vt);
2400 else
2401 FIXME("Unhandled time format %s.\n", debugstr_guid(&session->presentation.time_format));
2403 if (FAILED(hr = IMFPresentationClock_Start(session->clock, start_offset)))
2404 WARN("Failed to start session clock, hr %#x.\n", hr);
2406 return hr;
2409 static struct topo_node *session_get_node_object(struct media_session *session, IUnknown *object,
2410 MF_TOPOLOGY_TYPE node_type)
2412 struct topo_node *node = NULL;
2414 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2416 if (node->type == node_type && object == node->object.object)
2417 break;
2420 return node;
2423 static BOOL session_set_node_object_state(struct media_session *session, IUnknown *object,
2424 MF_TOPOLOGY_TYPE node_type, enum object_state state)
2426 struct topo_node *node;
2427 BOOL changed = FALSE;
2429 if ((node = session_get_node_object(session, object, node_type)))
2431 changed = node->state != state;
2432 node->state = state;
2435 return changed;
2438 static void session_set_source_object_state(struct media_session *session, IUnknown *object,
2439 MediaEventType event_type)
2441 IMFStreamSink *stream_sink;
2442 struct media_source *src;
2443 struct media_sink *sink;
2444 enum object_state state;
2445 struct topo_node *node;
2446 unsigned int i, count;
2447 BOOL changed = FALSE;
2448 HRESULT hr;
2450 if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
2451 return;
2453 switch (event_type)
2455 case MESourceStarted:
2456 case MESourcePaused:
2457 case MESourceStopped:
2459 LIST_FOR_EACH_ENTRY(src, &session->presentation.sources, struct media_source, entry)
2461 if (object == (IUnknown *)src->source)
2463 changed = src->state != state;
2464 src->state = state;
2465 break;
2468 break;
2469 case MEStreamStarted:
2470 case MEStreamPaused:
2471 case MEStreamStopped:
2473 changed = session_set_node_object_state(session, object, MF_TOPOLOGY_SOURCESTREAM_NODE, state);
2474 default:
2478 if (!changed)
2479 return;
2481 switch (session->state)
2483 case SESSION_STATE_STARTING_SOURCES:
2484 if (!session_is_source_nodes_state(session, OBJ_STATE_STARTED))
2485 break;
2487 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_STARTED_SOURCE);
2489 session_set_presentation_clock(session);
2491 if (session->presentation.flags & SESSION_FLAG_NEEDS_PREROLL)
2493 MFTIME preroll_time = 0;
2495 if (session->presentation.start_position.vt == VT_I8)
2496 preroll_time = session->presentation.start_position.hVal.QuadPart;
2498 /* Mark stream sinks without prerolling support as PREROLLED to keep state test logic generic. */
2499 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2501 if (sink->preroll)
2503 /* FIXME: abort and enter error state on failure. */
2504 if (FAILED(hr = IMFMediaSinkPreroll_NotifyPreroll(sink->preroll, preroll_time)))
2505 WARN("Preroll notification failed, hr %#x.\n", hr);
2507 else
2509 if (SUCCEEDED(IMFMediaSink_GetStreamSinkCount(sink->sink, &count)))
2511 for (i = 0; i < count; ++i)
2513 if (SUCCEEDED(IMFMediaSink_GetStreamSinkByIndex(sink->sink, i, &stream_sink)))
2515 session_set_node_object_state(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE,
2516 OBJ_STATE_PREROLLED);
2517 IMFStreamSink_Release(stream_sink);
2523 session->state = SESSION_STATE_PREROLLING_SINKS;
2525 else if (SUCCEEDED(session_start_clock(session)))
2526 session->state = SESSION_STATE_STARTING_SINKS;
2528 break;
2529 case SESSION_STATE_PAUSING_SOURCES:
2530 if (!session_is_source_nodes_state(session, OBJ_STATE_PAUSED))
2531 break;
2533 session_set_paused(session, S_OK);
2534 break;
2535 case SESSION_STATE_STOPPING_SOURCES:
2536 if (!session_is_source_nodes_state(session, OBJ_STATE_STOPPED))
2537 break;
2539 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2541 switch (node->type)
2543 case MF_TOPOLOGY_OUTPUT_NODE:
2544 IMFStreamSink_Flush(node->object.sink_stream);
2545 break;
2546 case MF_TOPOLOGY_TRANSFORM_NODE:
2547 IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_COMMAND_FLUSH, 0);
2548 break;
2549 default:
2554 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
2556 if (session->presentation.flags & SESSION_FLAG_FINALIZE_SINKS)
2557 session_finalize_sinks(session);
2558 else
2559 session_set_stopped(session, S_OK);
2561 break;
2562 default:
2567 static void session_set_sink_stream_state(struct media_session *session, IMFStreamSink *stream,
2568 MediaEventType event_type)
2570 struct media_source *source;
2571 enum object_state state;
2572 HRESULT hr = S_OK;
2573 BOOL changed;
2575 if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
2576 return;
2578 if (!(changed = session_set_node_object_state(session, (IUnknown *)stream, MF_TOPOLOGY_OUTPUT_NODE, state)))
2579 return;
2581 switch (session->state)
2583 case SESSION_STATE_PREROLLING_SINKS:
2584 if (!session_is_output_nodes_state(session, OBJ_STATE_PREROLLED))
2585 break;
2587 if (SUCCEEDED(session_start_clock(session)))
2588 session->state = SESSION_STATE_STARTING_SINKS;
2589 break;
2590 case SESSION_STATE_STARTING_SINKS:
2591 if (!session_is_output_nodes_state(session, OBJ_STATE_STARTED))
2592 break;
2594 session_set_started(session);
2595 break;
2596 case SESSION_STATE_PAUSING_SINKS:
2597 if (!session_is_output_nodes_state(session, OBJ_STATE_PAUSED))
2598 break;
2600 session->state = SESSION_STATE_PAUSING_SOURCES;
2602 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2604 if (FAILED(hr = IMFMediaSource_Pause(source->source)))
2605 break;
2608 if (FAILED(hr))
2609 session_set_paused(session, hr);
2611 break;
2612 case SESSION_STATE_STOPPING_SINKS:
2613 if (!session_is_output_nodes_state(session, OBJ_STATE_STOPPED))
2614 break;
2616 session->state = SESSION_STATE_STOPPING_SOURCES;
2618 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2620 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION)
2621 IMFMediaSource_Stop(source->source);
2622 else if (FAILED(hr = IMFMediaSource_Stop(source->source)))
2623 break;
2626 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION || FAILED(hr))
2627 session_set_stopped(session, hr);
2629 break;
2630 default:
2635 static DWORD transform_node_get_stream_id(struct topo_node *node, BOOL output, DWORD index)
2637 unsigned int *map = output ? node->u.transform.output_map : node->u.transform.input_map;
2638 return map ? map[index] : index;
2641 static struct sample *transform_create_sample(IMFSample *sample)
2643 struct sample *sample_entry = heap_alloc_zero(sizeof(*sample_entry));
2645 if (sample_entry)
2647 sample_entry->sample = sample;
2648 if (sample_entry->sample)
2649 IMFSample_AddRef(sample_entry->sample);
2652 return sample_entry;
2655 static HRESULT transform_get_external_output_sample(const struct media_session *session, struct topo_node *transform,
2656 unsigned int output_index, const MFT_OUTPUT_STREAM_INFO *stream_info, IMFSample **sample)
2658 IMFTopologyNode *downstream_node;
2659 unsigned int downstream_input;
2660 IMFMediaBuffer *buffer = NULL;
2661 struct topo_node *topo_node;
2662 TOPOID node_id;
2663 HRESULT hr;
2665 if (FAILED(IMFTopologyNode_GetOutput(transform->node, output_index, &downstream_node, &downstream_input)))
2667 WARN("Failed to get connected node for output %u.\n", output_index);
2668 return MF_E_UNEXPECTED;
2671 IMFTopologyNode_GetTopoNodeID(downstream_node, &node_id);
2672 IMFTopologyNode_Release(downstream_node);
2674 topo_node = session_get_node_by_id(session, node_id);
2676 if (topo_node->type == MF_TOPOLOGY_OUTPUT_NODE && topo_node->u.sink.allocator)
2678 hr = IMFVideoSampleAllocator_AllocateSample(topo_node->u.sink.allocator, sample);
2680 else
2682 hr = MFCreateAlignedMemoryBuffer(stream_info->cbSize, stream_info->cbAlignment, &buffer);
2683 if (SUCCEEDED(hr))
2684 hr = MFCreateSample(sample);
2686 if (SUCCEEDED(hr))
2687 hr = IMFSample_AddBuffer(*sample, buffer);
2689 if (buffer)
2690 IMFMediaBuffer_Release(buffer);
2693 return hr;
2696 static HRESULT transform_node_pull_samples(const struct media_session *session, struct topo_node *node)
2698 MFT_OUTPUT_STREAM_INFO stream_info;
2699 MFT_OUTPUT_DATA_BUFFER *buffers;
2700 struct sample *queued_sample;
2701 DWORD status = 0;
2702 unsigned int i;
2703 HRESULT hr = E_UNEXPECTED;
2705 if (!(buffers = heap_calloc(node->u.transform.output_count, sizeof(*buffers))))
2706 return E_OUTOFMEMORY;
2708 for (i = 0; i < node->u.transform.output_count; ++i)
2710 buffers[i].dwStreamID = transform_node_get_stream_id(node, TRUE, i);
2711 buffers[i].pSample = NULL;
2712 buffers[i].dwStatus = 0;
2713 buffers[i].pEvents = NULL;
2715 memset(&stream_info, 0, sizeof(stream_info));
2716 if (FAILED(hr = IMFTransform_GetOutputStreamInfo(node->object.transform, buffers[i].dwStreamID, &stream_info)))
2717 break;
2719 if (!(stream_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES))
2721 if (FAILED(hr = transform_get_external_output_sample(session, node, i, &stream_info, &buffers[i].pSample)))
2722 break;
2726 if (SUCCEEDED(hr))
2727 hr = IMFTransform_ProcessOutput(node->object.transform, 0, node->u.transform.output_count, buffers, &status);
2729 /* Collect returned samples for all streams. */
2730 for (i = 0; i < node->u.transform.output_count; ++i)
2732 if (buffers[i].pEvents)
2733 IMFCollection_Release(buffers[i].pEvents);
2735 if (SUCCEEDED(hr) && !(buffers[i].dwStatus & MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE))
2737 if (session->quality_manager)
2738 IMFQualityManager_NotifyProcessOutput(session->quality_manager, node->node, i, buffers[i].pSample);
2740 queued_sample = transform_create_sample(buffers[i].pSample);
2741 list_add_tail(&node->u.transform.outputs[i].samples, &queued_sample->entry);
2744 if (buffers[i].pSample)
2745 IMFSample_Release(buffers[i].pSample);
2748 heap_free(buffers);
2750 return hr;
2753 static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input,
2754 IMFSample *sample)
2756 struct sample *sample_entry, *sample_entry2;
2757 DWORD stream_id, downstream_input;
2758 IMFTopologyNode *downstream_node;
2759 struct topo_node *topo_node;
2760 MF_TOPOLOGY_TYPE node_type;
2761 BOOL drain = FALSE;
2762 TOPOID node_id;
2763 unsigned int i;
2764 HRESULT hr;
2766 if (session->quality_manager)
2767 IMFQualityManager_NotifyProcessInput(session->quality_manager, node, input, sample);
2769 IMFTopologyNode_GetNodeType(node, &node_type);
2770 IMFTopologyNode_GetTopoNodeID(node, &node_id);
2772 topo_node = session_get_node_by_id(session, node_id);
2774 switch (node_type)
2776 case MF_TOPOLOGY_OUTPUT_NODE:
2777 if (sample)
2779 if (topo_node->u.sink.requests)
2781 if (FAILED(hr = IMFStreamSink_ProcessSample(topo_node->object.sink_stream, sample)))
2782 WARN("Stream sink failed to process sample, hr %#x.\n", hr);
2783 topo_node->u.sink.requests--;
2786 else if (FAILED(hr = IMFStreamSink_PlaceMarker(topo_node->object.sink_stream, MFSTREAMSINK_MARKER_ENDOFSEGMENT,
2787 NULL, NULL)))
2789 WARN("Failed to place sink marker, hr %#x.\n", hr);
2791 break;
2792 case MF_TOPOLOGY_TRANSFORM_NODE:
2794 transform_node_pull_samples(session, topo_node);
2796 sample_entry = transform_create_sample(sample);
2797 list_add_tail(&topo_node->u.transform.inputs[input].samples, &sample_entry->entry);
2799 for (i = 0; i < topo_node->u.transform.input_count; ++i)
2801 stream_id = transform_node_get_stream_id(topo_node, FALSE, i);
2802 LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.inputs[i].samples,
2803 struct sample, entry)
2805 if (sample_entry->sample)
2807 if ((hr = IMFTransform_ProcessInput(topo_node->object.transform, stream_id,
2808 sample_entry->sample, 0)) == MF_E_NOTACCEPTING)
2809 break;
2810 if (FAILED(hr))
2811 WARN("Failed to process input for stream %u/%u, hr %#x.\n", i, stream_id, hr);
2812 transform_release_sample(sample_entry);
2814 else
2816 transform_stream_drop_samples(&topo_node->u.transform.inputs[i]);
2817 drain = TRUE;
2822 if (drain)
2824 if (FAILED(hr = IMFTransform_ProcessMessage(topo_node->object.transform, MFT_MESSAGE_COMMAND_DRAIN, 0)))
2825 WARN("Drain command failed for transform, hr %#x.\n", hr);
2828 transform_node_pull_samples(session, topo_node);
2830 /* Remaining unprocessed input has been discarded, now queue markers for every output. */
2831 if (drain)
2833 for (i = 0; i < topo_node->u.transform.output_count; ++i)
2835 if ((sample_entry = transform_create_sample(NULL)))
2836 list_add_tail(&topo_node->u.transform.outputs[i].samples, &sample_entry->entry);
2840 /* Push down all available output. */
2841 for (i = 0; i < topo_node->u.transform.output_count; ++i)
2843 if (FAILED(IMFTopologyNode_GetOutput(node, i, &downstream_node, &downstream_input)))
2845 WARN("Failed to get connected node for output %u.\n", i);
2846 continue;
2849 LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.outputs[i].samples,
2850 struct sample, entry)
2852 if (!topo_node->u.transform.outputs[i].requests)
2853 break;
2855 session_deliver_sample_to_node(session, downstream_node, downstream_input, sample_entry->sample);
2856 topo_node->u.transform.outputs[i].requests--;
2858 transform_release_sample(sample_entry);
2861 IMFTopologyNode_Release(downstream_node);
2864 break;
2865 case MF_TOPOLOGY_TEE_NODE:
2866 FIXME("Unhandled downstream node type %d.\n", node_type);
2867 break;
2868 default:
2873 static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output)
2875 IMFTopologyNode *downstream_node, *upstream_node;
2876 unsigned int downstream_input, upstream_output;
2877 struct topo_node *topo_node;
2878 MF_TOPOLOGY_TYPE node_type;
2879 struct sample *sample;
2880 TOPOID node_id;
2881 HRESULT hr;
2883 IMFTopologyNode_GetNodeType(node, &node_type);
2884 IMFTopologyNode_GetTopoNodeID(node, &node_id);
2886 topo_node = session_get_node_by_id(session, node_id);
2888 switch (node_type)
2890 case MF_TOPOLOGY_SOURCESTREAM_NODE:
2891 if (FAILED(hr = IMFMediaStream_RequestSample(topo_node->object.source_stream, NULL)))
2892 WARN("Sample request failed, hr %#x.\n", hr);
2893 break;
2894 case MF_TOPOLOGY_TRANSFORM_NODE:
2896 if (list_empty(&topo_node->u.transform.outputs[output].samples))
2898 /* Forward request to upstream node. */
2899 if (SUCCEEDED(hr = IMFTopologyNode_GetInput(node, 0 /* FIXME */, &upstream_node, &upstream_output)))
2901 if (SUCCEEDED(hr = session_request_sample_from_node(session, upstream_node, upstream_output)))
2902 topo_node->u.transform.outputs[output].requests++;
2903 IMFTopologyNode_Release(upstream_node);
2906 else
2908 if (SUCCEEDED(hr = IMFTopologyNode_GetOutput(node, output, &downstream_node, &downstream_input)))
2910 sample = LIST_ENTRY(list_head(&topo_node->u.transform.outputs[output].samples), struct sample, entry);
2911 session_deliver_sample_to_node(session, downstream_node, downstream_input, sample->sample);
2912 transform_release_sample(sample);
2913 IMFTopologyNode_Release(downstream_node);
2917 break;
2918 case MF_TOPOLOGY_TEE_NODE:
2919 FIXME("Unhandled upstream node type %d.\n", node_type);
2920 default:
2921 hr = E_UNEXPECTED;
2924 return hr;
2927 static void session_request_sample(struct media_session *session, IMFStreamSink *sink_stream)
2929 struct topo_node *sink_node = NULL, *node;
2930 IMFTopologyNode *upstream_node;
2931 DWORD upstream_output;
2932 HRESULT hr;
2934 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2936 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink_stream)
2938 sink_node = node;
2939 break;
2943 if (!sink_node)
2944 return;
2946 if (FAILED(hr = IMFTopologyNode_GetInput(sink_node->node, 0, &upstream_node, &upstream_output)))
2948 WARN("Failed to get upstream node connection, hr %#x.\n", hr);
2949 return;
2952 if (SUCCEEDED(session_request_sample_from_node(session, upstream_node, upstream_output)))
2953 sink_node->u.sink.requests++;
2954 IMFTopologyNode_Release(upstream_node);
2957 static void session_deliver_sample(struct media_session *session, IMFMediaStream *stream, const PROPVARIANT *value)
2959 struct topo_node *source_node = NULL, *node;
2960 IMFTopologyNode *downstream_node;
2961 DWORD downstream_input;
2962 HRESULT hr;
2964 if (value && (value->vt != VT_UNKNOWN || !value->punkVal))
2966 WARN("Unexpected value type %d.\n", value->vt);
2967 return;
2970 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2972 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->object.source_stream == stream)
2974 source_node = node;
2975 break;
2979 if (!source_node)
2980 return;
2982 if (!value)
2983 source_node->flags |= TOPO_NODE_END_OF_STREAM;
2985 if (FAILED(hr = IMFTopologyNode_GetOutput(source_node->node, 0, &downstream_node, &downstream_input)))
2987 WARN("Failed to get downstream node connection, hr %#x.\n", hr);
2988 return;
2991 session_deliver_sample_to_node(session, downstream_node, downstream_input, value ? (IMFSample *)value->punkVal : NULL);
2992 IMFTopologyNode_Release(downstream_node);
2995 static void session_sink_invalidated(struct media_session *session, IMFMediaEvent *event, IMFStreamSink *sink)
2997 struct topo_node *node, *sink_node = NULL;
2998 HRESULT hr;
3000 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
3002 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink)
3004 sink_node = node;
3005 break;
3009 if (!sink_node)
3010 return;
3012 if (!event)
3014 if (FAILED(hr = MFCreateMediaEvent(MESinkInvalidated, &GUID_NULL, S_OK, NULL, &event)))
3015 WARN("Failed to create event, hr %#x.\n", hr);
3018 if (!event)
3019 return;
3021 IMFMediaEvent_SetUINT64(event, &MF_EVENT_OUTPUT_NODE, sink_node->node_id);
3022 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3024 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED);
3027 static BOOL session_nodes_is_mask_set(struct media_session *session, MF_TOPOLOGY_TYPE node_type, unsigned int flags)
3029 struct media_source *source;
3030 struct topo_node *node;
3032 if (node_type == MF_TOPOLOGY_MAX)
3034 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3036 if ((source->flags & flags) != flags)
3037 return FALSE;
3040 else
3042 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
3044 if (node->type == node_type && (node->flags & flags) != flags)
3045 return FALSE;
3049 return TRUE;
3052 static void session_raise_end_of_presentation(struct media_session *session)
3054 if (!(session_nodes_is_mask_set(session, MF_TOPOLOGY_SOURCESTREAM_NODE, TOPO_NODE_END_OF_STREAM)))
3055 return;
3057 if (!(session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION))
3059 if (session_nodes_is_mask_set(session, MF_TOPOLOGY_MAX, SOURCE_FLAG_END_OF_PRESENTATION))
3061 session->presentation.flags |= SESSION_FLAG_END_OF_PRESENTATION;
3062 session_push_back_command(session, SESSION_CMD_END);
3063 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, NULL);
3068 static void session_handle_end_of_stream(struct media_session *session, IMFMediaStream *stream)
3070 struct topo_node *node;
3072 if (!(node = session_get_node_object(session, (IUnknown *)stream, MF_TOPOLOGY_SOURCESTREAM_NODE))
3073 || node->flags & TOPO_NODE_END_OF_STREAM)
3075 return;
3078 session_deliver_sample(session, stream, NULL);
3080 session_raise_end_of_presentation(session);
3083 static void session_handle_end_of_presentation(struct media_session *session, IMFMediaSource *object)
3085 struct media_source *source;
3087 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3089 if (source->source == object)
3091 if (!(source->flags & SOURCE_FLAG_END_OF_PRESENTATION))
3093 source->flags |= SOURCE_FLAG_END_OF_PRESENTATION;
3094 session_raise_end_of_presentation(session);
3097 break;
3102 static void session_sink_stream_marker(struct media_session *session, IMFStreamSink *stream_sink)
3104 struct topo_node *node;
3106 if (!(node = session_get_node_object(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE))
3107 || node->flags & TOPO_NODE_END_OF_STREAM)
3109 return;
3112 node->flags |= TOPO_NODE_END_OF_STREAM;
3114 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION &&
3115 session_nodes_is_mask_set(session, MF_TOPOLOGY_OUTPUT_NODE, TOPO_NODE_END_OF_STREAM))
3117 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED);
3118 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
3119 session_stop(session);
3123 static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
3125 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
3126 IMFMediaEventGenerator *event_source;
3127 IMFMediaEvent *event = NULL;
3128 MediaEventType event_type;
3129 IUnknown *object = NULL;
3130 IMFMediaSource *source;
3131 IMFMediaStream *stream;
3132 PROPVARIANT value;
3133 HRESULT hr;
3135 if (FAILED(hr = IMFAsyncResult_GetState(result, (IUnknown **)&event_source)))
3136 return hr;
3138 if (FAILED(hr = IMFMediaEventGenerator_EndGetEvent(event_source, result, &event)))
3140 WARN("Failed to get event from %p, hr %#x.\n", event_source, hr);
3141 goto failed;
3144 if (FAILED(hr = IMFMediaEvent_GetType(event, &event_type)))
3146 WARN("Failed to get event type, hr %#x.\n", hr);
3147 goto failed;
3150 value.vt = VT_EMPTY;
3151 if (FAILED(hr = IMFMediaEvent_GetValue(event, &value)))
3153 WARN("Failed to get event value, hr %#x.\n", hr);
3154 goto failed;
3157 switch (event_type)
3159 case MESourceStarted:
3160 case MESourcePaused:
3161 case MESourceStopped:
3162 case MEStreamStarted:
3163 case MEStreamPaused:
3164 case MEStreamStopped:
3166 EnterCriticalSection(&session->cs);
3167 session_set_source_object_state(session, (IUnknown *)event_source, event_type);
3168 LeaveCriticalSection(&session->cs);
3170 break;
3172 case MEBufferingStarted:
3173 case MEBufferingStopped:
3175 EnterCriticalSection(&session->cs);
3176 if (session_get_media_source(session, (IMFMediaSource *)event_source))
3178 if (event_type == MEBufferingStarted)
3179 IMFPresentationClock_Pause(session->clock);
3180 else
3181 IMFPresentationClock_Start(session->clock, PRESENTATION_CURRENT_POSITION);
3183 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3185 LeaveCriticalSection(&session->cs);
3186 break;
3188 case MENewStream:
3189 stream = (IMFMediaStream *)value.punkVal;
3191 if (value.vt != VT_UNKNOWN || !stream)
3193 WARN("Unexpected event value.\n");
3194 break;
3197 if (FAILED(hr = IMFMediaStream_GetMediaSource(stream, &source)))
3198 break;
3200 EnterCriticalSection(&session->cs);
3201 if (SUCCEEDED(hr = session_add_media_stream(session, source, stream)))
3202 hr = IMFMediaStream_BeginGetEvent(stream, &session->events_callback, (IUnknown *)stream);
3203 LeaveCriticalSection(&session->cs);
3205 IMFMediaSource_Release(source);
3207 break;
3208 case MEStreamSinkStarted:
3209 case MEStreamSinkPaused:
3210 case MEStreamSinkStopped:
3211 case MEStreamSinkPrerolled:
3213 EnterCriticalSection(&session->cs);
3214 session_set_sink_stream_state(session, (IMFStreamSink *)event_source, event_type);
3215 LeaveCriticalSection(&session->cs);
3217 break;
3218 case MEStreamSinkMarker:
3220 EnterCriticalSection(&session->cs);
3221 session_sink_stream_marker(session, (IMFStreamSink *)event_source);
3222 LeaveCriticalSection(&session->cs);
3224 break;
3225 case MEStreamSinkRequestSample:
3227 EnterCriticalSection(&session->cs);
3228 session_request_sample(session, (IMFStreamSink *)event_source);
3229 LeaveCriticalSection(&session->cs);
3231 break;
3232 case MEMediaSample:
3234 EnterCriticalSection(&session->cs);
3235 session_deliver_sample(session, (IMFMediaStream *)event_source, &value);
3236 LeaveCriticalSection(&session->cs);
3238 break;
3239 case MEEndOfStream:
3241 EnterCriticalSection(&session->cs);
3242 session_handle_end_of_stream(session, (IMFMediaStream *)event_source);
3243 LeaveCriticalSection(&session->cs);
3245 break;
3247 case MEEndOfPresentation:
3249 EnterCriticalSection(&session->cs);
3250 session_handle_end_of_presentation(session, (IMFMediaSource *)event_source);
3251 LeaveCriticalSection(&session->cs);
3253 break;
3254 case MEAudioSessionGroupingParamChanged:
3255 case MEAudioSessionIconChanged:
3256 case MEAudioSessionNameChanged:
3257 case MEAudioSessionVolumeChanged:
3259 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3261 break;
3262 case MEAudioSessionDeviceRemoved:
3263 case MEAudioSessionDisconnected:
3264 case MEAudioSessionExclusiveModeOverride:
3265 case MEAudioSessionFormatChanged:
3266 case MEAudioSessionServerShutdown:
3268 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3269 /* fallthrough */
3270 case MESinkInvalidated:
3272 EnterCriticalSection(&session->cs);
3273 session_sink_invalidated(session, event_type == MESinkInvalidated ? event : NULL,
3274 (IMFStreamSink *)event_source);
3275 LeaveCriticalSection(&session->cs);
3277 break;
3278 case MEQualityNotify:
3280 if (session->quality_manager)
3282 if (FAILED(IMFMediaEventGenerator_QueryInterface(event_source, &IID_IMFStreamSink, (void **)&object)))
3283 IMFMediaEventGenerator_QueryInterface(event_source, &IID_IMFTransform, (void **)&object);
3285 if (object)
3287 IMFQualityManager_NotifyQualityEvent(session->quality_manager, object, event);
3288 IUnknown_Release(object);
3292 break;
3293 default:
3297 PropVariantClear(&value);
3299 failed:
3300 if (event)
3301 IMFMediaEvent_Release(event);
3303 if (FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(event_source, iface, (IUnknown *)event_source)))
3304 WARN("Failed to re-subscribe, hr %#x.\n", hr);
3306 IMFMediaEventGenerator_Release(event_source);
3308 return hr;
3311 static const IMFAsyncCallbackVtbl session_events_callback_vtbl =
3313 session_events_callback_QueryInterface,
3314 session_events_callback_AddRef,
3315 session_events_callback_Release,
3316 session_events_callback_GetParameters,
3317 session_events_callback_Invoke,
3320 static HRESULT WINAPI session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
3322 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
3323 IsEqualIID(riid, &IID_IUnknown))
3325 *obj = iface;
3326 IMFAsyncCallback_AddRef(iface);
3327 return S_OK;
3330 WARN("Unsupported %s.\n", debugstr_guid(riid));
3331 *obj = NULL;
3332 return E_NOINTERFACE;
3335 static ULONG WINAPI session_sink_finalizer_callback_AddRef(IMFAsyncCallback *iface)
3337 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3338 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3341 static ULONG WINAPI session_sink_finalizer_callback_Release(IMFAsyncCallback *iface)
3343 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3344 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3347 static HRESULT WINAPI session_sink_finalizer_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
3349 return E_NOTIMPL;
3352 static HRESULT WINAPI session_sink_finalizer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
3354 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3355 IMFFinalizableMediaSink *fin_sink = NULL;
3356 BOOL sinks_finalized = TRUE;
3357 struct media_sink *sink;
3358 IUnknown *state;
3359 HRESULT hr;
3361 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
3362 return hr;
3364 EnterCriticalSection(&session->cs);
3366 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
3368 if (state == (IUnknown *)sink->sink)
3370 if (FAILED(hr = IMFMediaSink_QueryInterface(sink->sink, &IID_IMFFinalizableMediaSink, (void **)&fin_sink)))
3371 WARN("Unexpected, missing IMFFinalizableSink, hr %#x.\n", hr);
3373 else
3375 sinks_finalized &= sink->finalized;
3376 if (!sinks_finalized)
3377 break;
3381 IUnknown_Release(state);
3383 if (fin_sink)
3385 /* Complete session transition, or close prematurely on error. */
3386 if (SUCCEEDED(hr = IMFFinalizableMediaSink_EndFinalize(fin_sink, result)))
3388 sink->finalized = TRUE;
3389 if (sinks_finalized)
3390 session_set_closed(session, hr);
3392 IMFFinalizableMediaSink_Release(fin_sink);
3395 LeaveCriticalSection(&session->cs);
3397 return S_OK;
3400 static const IMFAsyncCallbackVtbl session_sink_finalizer_callback_vtbl =
3402 session_sink_finalizer_callback_QueryInterface,
3403 session_sink_finalizer_callback_AddRef,
3404 session_sink_finalizer_callback_Release,
3405 session_sink_finalizer_callback_GetParameters,
3406 session_sink_finalizer_callback_Invoke,
3409 static HRESULT WINAPI session_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
3411 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3412 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
3415 static ULONG WINAPI session_rate_support_AddRef(IMFRateSupport *iface)
3417 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3418 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3421 static ULONG WINAPI session_rate_support_Release(IMFRateSupport *iface)
3423 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3424 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3427 static HRESULT session_presentation_object_get_rate(IUnknown *object, MFRATE_DIRECTION direction,
3428 BOOL thin, BOOL fastest, float *result)
3430 IMFRateSupport *rate_support;
3431 float rate;
3432 HRESULT hr;
3434 /* For objects that don't support rate control, it's assumed that only forward direction is allowed, at 1.0f. */
3436 if (FAILED(hr = MFGetService(object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support)))
3438 if (direction == MFRATE_FORWARD)
3440 *result = 1.0f;
3441 return S_OK;
3443 else
3444 return MF_E_REVERSE_UNSUPPORTED;
3447 rate = 0.0f;
3448 if (fastest)
3450 if (SUCCEEDED(hr = IMFRateSupport_GetFastestRate(rate_support, direction, thin, &rate)))
3451 *result = min(fabsf(rate), *result);
3453 else
3455 if (SUCCEEDED(hr = IMFRateSupport_GetSlowestRate(rate_support, direction, thin, &rate)))
3456 *result = max(fabsf(rate), *result);
3459 IMFRateSupport_Release(rate_support);
3461 return hr;
3464 static HRESULT session_get_presentation_rate(struct media_session *session, MFRATE_DIRECTION direction,
3465 BOOL thin, BOOL fastest, float *result)
3467 struct media_source *source;
3468 struct media_sink *sink;
3469 HRESULT hr = E_POINTER;
3471 *result = 0.0f;
3473 EnterCriticalSection(&session->cs);
3475 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
3477 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3479 if (FAILED(hr = session_presentation_object_get_rate((IUnknown *)source->source, direction, thin, fastest, result)))
3480 break;
3483 if (SUCCEEDED(hr))
3485 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
3487 if (FAILED(hr = session_presentation_object_get_rate((IUnknown *)sink->sink, direction, thin, fastest, result)))
3488 break;
3493 LeaveCriticalSection(&session->cs);
3495 return hr;
3498 static HRESULT WINAPI session_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
3499 BOOL thin, float *rate)
3501 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3503 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
3505 return session_get_presentation_rate(session, direction, thin, FALSE, rate);
3508 static HRESULT WINAPI session_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
3509 BOOL thin, float *rate)
3511 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3513 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
3515 return session_get_presentation_rate(session, direction, thin, TRUE, rate);
3518 static HRESULT WINAPI session_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
3519 float *nearest_supported_rate)
3521 FIXME("%p, %d, %f, %p.\n", iface, thin, rate, nearest_supported_rate);
3523 return E_NOTIMPL;
3526 static const IMFRateSupportVtbl session_rate_support_vtbl =
3528 session_rate_support_QueryInterface,
3529 session_rate_support_AddRef,
3530 session_rate_support_Release,
3531 session_rate_support_GetSlowestRate,
3532 session_rate_support_GetFastestRate,
3533 session_rate_support_IsRateSupported,
3536 static HRESULT WINAPI session_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj)
3538 struct media_session *session = impl_session_from_IMFRateControl(iface);
3539 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
3542 static ULONG WINAPI session_rate_control_AddRef(IMFRateControl *iface)
3544 struct media_session *session = impl_session_from_IMFRateControl(iface);
3545 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3548 static ULONG WINAPI session_rate_control_Release(IMFRateControl *iface)
3550 struct media_session *session = impl_session_from_IMFRateControl(iface);
3551 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3554 static HRESULT WINAPI session_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate)
3556 FIXME("%p, %d, %f.\n", iface, thin, rate);
3558 return E_NOTIMPL;
3561 static HRESULT WINAPI session_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
3563 struct media_session *session = impl_session_from_IMFRateControl(iface);
3565 TRACE("%p, %p, %p.\n", iface, thin, rate);
3567 return IMFRateControl_GetRate(session->clock_rate_control, thin, rate);
3570 static const IMFRateControlVtbl session_rate_control_vtbl =
3572 session_rate_control_QueryInterface,
3573 session_rate_control_AddRef,
3574 session_rate_control_Release,
3575 session_rate_control_SetRate,
3576 session_rate_control_GetRate,
3579 static HRESULT WINAPI node_attribute_editor_QueryInterface(IMFTopologyNodeAttributeEditor *iface,
3580 REFIID riid, void **obj)
3582 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
3584 if (IsEqualIID(riid, &IID_IMFTopologyNodeAttributeEditor) ||
3585 IsEqualIID(riid, &IID_IUnknown))
3587 *obj = iface;
3588 IMFTopologyNodeAttributeEditor_AddRef(iface);
3589 return S_OK;
3592 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
3593 *obj = NULL;
3594 return E_NOINTERFACE;
3597 static ULONG WINAPI node_attribute_editor_AddRef(IMFTopologyNodeAttributeEditor *iface)
3599 struct media_session *session = impl_session_from_IMFTopologyNodeAttributeEditor(iface);
3600 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3603 static ULONG WINAPI node_attribute_editor_Release(IMFTopologyNodeAttributeEditor *iface)
3605 struct media_session *session = impl_session_from_IMFTopologyNodeAttributeEditor(iface);
3606 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3609 static HRESULT WINAPI node_attribute_editor_UpdateNodeAttributes(IMFTopologyNodeAttributeEditor *iface,
3610 TOPOID id, DWORD count, MFTOPONODE_ATTRIBUTE_UPDATE *updates)
3612 FIXME("%p, %s, %u, %p.\n", iface, wine_dbgstr_longlong(id), count, updates);
3614 return E_NOTIMPL;
3617 static const IMFTopologyNodeAttributeEditorVtbl node_attribute_editor_vtbl =
3619 node_attribute_editor_QueryInterface,
3620 node_attribute_editor_AddRef,
3621 node_attribute_editor_Release,
3622 node_attribute_editor_UpdateNodeAttributes,
3625 /***********************************************************************
3626 * MFCreateMediaSession (mf.@)
3628 HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **session)
3630 BOOL without_quality_manager = FALSE;
3631 struct media_session *object;
3632 HRESULT hr;
3634 TRACE("%p, %p.\n", config, session);
3636 object = heap_alloc_zero(sizeof(*object));
3637 if (!object)
3638 return E_OUTOFMEMORY;
3640 object->IMFMediaSession_iface.lpVtbl = &mfmediasessionvtbl;
3641 object->IMFGetService_iface.lpVtbl = &session_get_service_vtbl;
3642 object->IMFRateSupport_iface.lpVtbl = &session_rate_support_vtbl;
3643 object->IMFRateControl_iface.lpVtbl = &session_rate_control_vtbl;
3644 object->IMFTopologyNodeAttributeEditor_iface.lpVtbl = &node_attribute_editor_vtbl;
3645 object->commands_callback.lpVtbl = &session_commands_callback_vtbl;
3646 object->events_callback.lpVtbl = &session_events_callback_vtbl;
3647 object->sink_finalizer_callback.lpVtbl = &session_sink_finalizer_callback_vtbl;
3648 object->refcount = 1;
3649 list_init(&object->topologies);
3650 list_init(&object->commands);
3651 list_init(&object->presentation.sources);
3652 list_init(&object->presentation.sinks);
3653 list_init(&object->presentation.nodes);
3654 InitializeCriticalSection(&object->cs);
3656 if (FAILED(hr = MFCreateTopology(&object->presentation.current_topology)))
3657 goto failed;
3659 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
3660 goto failed;
3662 if (FAILED(hr = MFCreatePresentationClock(&object->clock)))
3663 goto failed;
3665 if (FAILED(hr = MFCreateSystemTimeSource(&object->system_time_source)))
3666 goto failed;
3668 if (FAILED(hr = IMFPresentationClock_QueryInterface(object->clock, &IID_IMFRateControl,
3669 (void **)&object->clock_rate_control)))
3671 goto failed;
3674 if (config)
3676 GUID clsid;
3678 if (SUCCEEDED(IMFAttributes_GetGUID(config, &MF_SESSION_TOPOLOADER, &clsid)))
3680 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTopoLoader,
3681 (void **)&object->topo_loader)))
3683 WARN("Failed to create custom topology loader, hr %#x.\n", hr);
3687 if (SUCCEEDED(IMFAttributes_GetGUID(config, &MF_SESSION_QUALITY_MANAGER, &clsid)))
3689 if (!(without_quality_manager = IsEqualGUID(&clsid, &GUID_NULL)))
3691 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFQualityManager,
3692 (void **)&object->quality_manager)))
3694 WARN("Failed to create custom quality manager, hr %#x.\n", hr);
3700 if (!object->topo_loader && FAILED(hr = MFCreateTopoLoader(&object->topo_loader)))
3701 goto failed;
3703 if (!object->quality_manager && !without_quality_manager &&
3704 FAILED(hr = MFCreateStandardQualityManager(&object->quality_manager)))
3706 goto failed;
3709 if (object->quality_manager && FAILED(hr = IMFQualityManager_NotifyPresentationClock(object->quality_manager,
3710 object->clock)))
3712 goto failed;
3715 *session = &object->IMFMediaSession_iface;
3717 return S_OK;
3719 failed:
3720 IMFMediaSession_Release(&object->IMFMediaSession_iface);
3721 return hr;
3724 static HRESULT WINAPI sink_notification_QueryInterface(IUnknown *iface, REFIID riid, void **out)
3726 if (IsEqualIID(riid, &IID_IUnknown))
3728 *out = iface;
3729 IUnknown_AddRef(iface);
3730 return S_OK;
3733 WARN("Unsupported %s.\n", debugstr_guid(riid));
3734 *out = NULL;
3735 return E_NOINTERFACE;
3738 static ULONG WINAPI sink_notification_AddRef(IUnknown *iface)
3740 struct sink_notification *notification = impl_sink_notification_from_IUnknown(iface);
3741 ULONG refcount = InterlockedIncrement(&notification->refcount);
3743 TRACE("%p, refcount %u.\n", iface, refcount);
3745 return refcount;
3748 static ULONG WINAPI sink_notification_Release(IUnknown *iface)
3750 struct sink_notification *notification = impl_sink_notification_from_IUnknown(iface);
3751 ULONG refcount = InterlockedDecrement(&notification->refcount);
3753 TRACE("%p, refcount %u.\n", iface, refcount);
3755 if (!refcount)
3757 IMFClockStateSink_Release(notification->sink);
3758 heap_free(notification);
3761 return refcount;
3764 static const IUnknownVtbl sinknotificationvtbl =
3766 sink_notification_QueryInterface,
3767 sink_notification_AddRef,
3768 sink_notification_Release,
3771 static void clock_notify_async_sink(struct presentation_clock *clock, MFTIME system_time,
3772 struct clock_state_change_param param, enum clock_notification notification, IMFClockStateSink *sink)
3774 struct sink_notification *object;
3775 IMFAsyncResult *result;
3776 HRESULT hr;
3778 object = heap_alloc(sizeof(*object));
3779 if (!object)
3780 return;
3782 object->IUnknown_iface.lpVtbl = &sinknotificationvtbl;
3783 object->refcount = 1;
3784 object->system_time = system_time;
3785 object->param = param;
3786 object->notification = notification;
3787 object->sink = sink;
3788 IMFClockStateSink_AddRef(object->sink);
3790 hr = MFCreateAsyncResult(&object->IUnknown_iface, &clock->sink_callback, NULL, &result);
3791 IUnknown_Release(&object->IUnknown_iface);
3792 if (SUCCEEDED(hr))
3794 MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD, result);
3795 IMFAsyncResult_Release(result);
3799 static HRESULT WINAPI present_clock_QueryInterface(IMFPresentationClock *iface, REFIID riid, void **out)
3801 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3803 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
3805 if (IsEqualIID(riid, &IID_IMFPresentationClock) ||
3806 IsEqualIID(riid, &IID_IMFClock) ||
3807 IsEqualIID(riid, &IID_IUnknown))
3809 *out = &clock->IMFPresentationClock_iface;
3811 else if (IsEqualIID(riid, &IID_IMFRateControl))
3813 *out = &clock->IMFRateControl_iface;
3815 else if (IsEqualIID(riid, &IID_IMFTimer))
3817 *out = &clock->IMFTimer_iface;
3819 else if (IsEqualIID(riid, &IID_IMFShutdown))
3821 *out = &clock->IMFShutdown_iface;
3823 else
3825 WARN("Unsupported %s.\n", debugstr_guid(riid));
3826 *out = NULL;
3827 return E_NOINTERFACE;
3830 IUnknown_AddRef((IUnknown *)*out);
3831 return S_OK;
3834 static ULONG WINAPI present_clock_AddRef(IMFPresentationClock *iface)
3836 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3837 ULONG refcount = InterlockedIncrement(&clock->refcount);
3839 TRACE("%p, refcount %u.\n", iface, refcount);
3841 return refcount;
3844 static ULONG WINAPI present_clock_Release(IMFPresentationClock *iface)
3846 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3847 ULONG refcount = InterlockedDecrement(&clock->refcount);
3848 struct clock_timer *timer, *timer2;
3849 struct clock_sink *sink, *sink2;
3851 TRACE("%p, refcount %u.\n", iface, refcount);
3853 if (!refcount)
3855 if (clock->time_source)
3856 IMFPresentationTimeSource_Release(clock->time_source);
3857 if (clock->time_source_sink)
3858 IMFClockStateSink_Release(clock->time_source_sink);
3859 LIST_FOR_EACH_ENTRY_SAFE(sink, sink2, &clock->sinks, struct clock_sink, entry)
3861 list_remove(&sink->entry);
3862 IMFClockStateSink_Release(sink->state_sink);
3863 heap_free(sink);
3865 LIST_FOR_EACH_ENTRY_SAFE(timer, timer2, &clock->timers, struct clock_timer, entry)
3867 list_remove(&timer->entry);
3868 IUnknown_Release(&timer->IUnknown_iface);
3870 DeleteCriticalSection(&clock->cs);
3871 heap_free(clock);
3874 return refcount;
3877 static HRESULT WINAPI present_clock_GetClockCharacteristics(IMFPresentationClock *iface, DWORD *flags)
3879 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3880 HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
3882 TRACE("%p, %p.\n", iface, flags);
3884 EnterCriticalSection(&clock->cs);
3885 if (clock->time_source)
3886 hr = IMFPresentationTimeSource_GetClockCharacteristics(clock->time_source, flags);
3887 LeaveCriticalSection(&clock->cs);
3889 return hr;
3892 static HRESULT WINAPI present_clock_GetCorrelatedTime(IMFPresentationClock *iface, DWORD reserved,
3893 LONGLONG *clock_time, MFTIME *system_time)
3895 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3896 HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
3898 TRACE("%p, %#x, %p, %p.\n", iface, reserved, clock_time, system_time);
3900 EnterCriticalSection(&clock->cs);
3901 if (clock->time_source)
3902 hr = IMFPresentationTimeSource_GetCorrelatedTime(clock->time_source, reserved, clock_time, system_time);
3903 LeaveCriticalSection(&clock->cs);
3905 return hr;
3908 static HRESULT WINAPI present_clock_GetContinuityKey(IMFPresentationClock *iface, DWORD *key)
3910 TRACE("%p, %p.\n", iface, key);
3912 *key = 0;
3914 return S_OK;
3917 static HRESULT WINAPI present_clock_GetState(IMFPresentationClock *iface, DWORD reserved, MFCLOCK_STATE *state)
3919 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3921 TRACE("%p, %#x, %p.\n", iface, reserved, state);
3923 EnterCriticalSection(&clock->cs);
3924 *state = clock->state;
3925 LeaveCriticalSection(&clock->cs);
3927 return S_OK;
3930 static HRESULT WINAPI present_clock_GetProperties(IMFPresentationClock *iface, MFCLOCK_PROPERTIES *props)
3932 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3933 HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
3935 TRACE("%p, %p.\n", iface, props);
3937 EnterCriticalSection(&clock->cs);
3938 if (clock->time_source)
3939 hr = IMFPresentationTimeSource_GetProperties(clock->time_source, props);
3940 LeaveCriticalSection(&clock->cs);
3942 return hr;
3945 static HRESULT WINAPI present_clock_SetTimeSource(IMFPresentationClock *iface,
3946 IMFPresentationTimeSource *time_source)
3948 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3949 MFCLOCK_PROPERTIES props;
3950 IMFClock *source_clock;
3951 HRESULT hr;
3953 TRACE("%p, %p.\n", iface, time_source);
3955 EnterCriticalSection(&clock->cs);
3957 if (clock->time_source)
3958 IMFPresentationTimeSource_Release(clock->time_source);
3959 if (clock->time_source_sink)
3960 IMFClockStateSink_Release(clock->time_source_sink);
3961 clock->time_source = NULL;
3962 clock->time_source_sink = NULL;
3964 hr = IMFPresentationTimeSource_QueryInterface(time_source, &IID_IMFClockStateSink, (void **)&clock->time_source_sink);
3965 if (SUCCEEDED(hr))
3967 clock->time_source = time_source;
3968 IMFPresentationTimeSource_AddRef(clock->time_source);
3971 if (SUCCEEDED(IMFPresentationTimeSource_GetUnderlyingClock(time_source, &source_clock)))
3973 if (SUCCEEDED(IMFClock_GetProperties(source_clock, &props)))
3974 clock->frequency = props.qwClockFrequency;
3975 IMFClock_Release(source_clock);
3978 if (!clock->frequency)
3979 clock->frequency = MFCLOCK_FREQUENCY_HNS;
3981 LeaveCriticalSection(&clock->cs);
3983 return hr;
3986 static HRESULT WINAPI present_clock_GetTimeSource(IMFPresentationClock *iface,
3987 IMFPresentationTimeSource **time_source)
3989 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3990 HRESULT hr = S_OK;
3992 TRACE("%p, %p.\n", iface, time_source);
3994 if (!time_source)
3995 return E_INVALIDARG;
3997 EnterCriticalSection(&clock->cs);
3998 if (clock->time_source)
4000 *time_source = clock->time_source;
4001 IMFPresentationTimeSource_AddRef(*time_source);
4003 else
4004 hr = MF_E_CLOCK_NO_TIME_SOURCE;
4005 LeaveCriticalSection(&clock->cs);
4007 return hr;
4010 static HRESULT WINAPI present_clock_GetTime(IMFPresentationClock *iface, MFTIME *time)
4012 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
4013 HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
4014 MFTIME systime;
4016 TRACE("%p, %p.\n", iface, time);
4018 if (!time)
4019 return E_POINTER;
4021 EnterCriticalSection(&clock->cs);
4022 if (clock->time_source)
4023 hr = IMFPresentationTimeSource_GetCorrelatedTime(clock->time_source, 0, time, &systime);
4024 LeaveCriticalSection(&clock->cs);
4026 return hr;
4029 static HRESULT WINAPI present_clock_AddClockStateSink(IMFPresentationClock *iface, IMFClockStateSink *state_sink)
4031 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
4032 struct clock_sink *sink, *cur;
4033 HRESULT hr = S_OK;
4035 TRACE("%p, %p.\n", iface, state_sink);
4037 if (!state_sink)
4038 return E_INVALIDARG;
4040 sink = heap_alloc(sizeof(*sink));
4041 if (!sink)
4042 return E_OUTOFMEMORY;
4044 sink->state_sink = state_sink;
4045 IMFClockStateSink_AddRef(sink->state_sink);
4047 EnterCriticalSection(&clock->cs);
4048 LIST_FOR_EACH_ENTRY(cur, &clock->sinks, struct clock_sink, entry)
4050 if (cur->state_sink == state_sink)
4052 hr = E_INVALIDARG;
4053 break;
4056 if (SUCCEEDED(hr))
4058 static const enum clock_notification notifications[MFCLOCK_STATE_PAUSED + 1] =
4060 /* MFCLOCK_STATE_INVALID */ 0, /* Does not apply */
4061 /* MFCLOCK_STATE_RUNNING */ CLOCK_NOTIFY_START,
4062 /* MFCLOCK_STATE_STOPPED */ CLOCK_NOTIFY_STOP,
4063 /* MFCLOCK_STATE_PAUSED */ CLOCK_NOTIFY_PAUSE,
4065 struct clock_state_change_param param;
4067 if (!clock->is_shut_down && clock->state != MFCLOCK_STATE_INVALID)
4069 param.u.offset = clock->start_offset;
4070 clock_notify_async_sink(clock, MFGetSystemTime(), param, notifications[clock->state], sink->state_sink);
4073 list_add_tail(&clock->sinks, &sink->entry);
4075 LeaveCriticalSection(&clock->cs);
4077 if (FAILED(hr))
4079 IMFClockStateSink_Release(sink->state_sink);
4080 heap_free(sink);
4083 return hr;
4086 static HRESULT WINAPI present_clock_RemoveClockStateSink(IMFPresentationClock *iface,
4087 IMFClockStateSink *state_sink)
4089 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
4090 struct clock_sink *sink;
4092 TRACE("%p, %p.\n", iface, state_sink);
4094 if (!state_sink)
4095 return E_INVALIDARG;
4097 EnterCriticalSection(&clock->cs);
4098 LIST_FOR_EACH_ENTRY(sink, &clock->sinks, struct clock_sink, entry)
4100 if (sink->state_sink == state_sink)
4102 IMFClockStateSink_Release(sink->state_sink);
4103 list_remove(&sink->entry);
4104 heap_free(sink);
4105 break;
4108 LeaveCriticalSection(&clock->cs);
4110 return S_OK;
4113 static HRESULT clock_call_state_change(MFTIME system_time, struct clock_state_change_param param,
4114 enum clock_notification notification, IMFClockStateSink *sink)
4116 HRESULT hr = S_OK;
4118 switch (notification)
4120 case CLOCK_NOTIFY_START:
4121 hr = IMFClockStateSink_OnClockStart(sink, system_time, param.u.offset);
4122 break;
4123 case CLOCK_NOTIFY_STOP:
4124 hr = IMFClockStateSink_OnClockStop(sink, system_time);
4125 break;
4126 case CLOCK_NOTIFY_PAUSE:
4127 hr = IMFClockStateSink_OnClockPause(sink, system_time);
4128 break;
4129 case CLOCK_NOTIFY_RESTART:
4130 hr = IMFClockStateSink_OnClockRestart(sink, system_time);
4131 break;
4132 case CLOCK_NOTIFY_SET_RATE:
4133 /* System time source does not allow 0.0 rate, presentation clock allows it without raising errors. */
4134 IMFClockStateSink_OnClockSetRate(sink, system_time, param.u.rate);
4135 break;
4136 default:
4140 return hr;
4143 static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_command command,
4144 struct clock_state_change_param param)
4146 static const BYTE state_change_is_allowed[MFCLOCK_STATE_PAUSED+1][CLOCK_CMD_MAX] =
4147 { /* S S* P, R */
4148 /* INVALID */ { 1, 1, 1, 1 },
4149 /* RUNNING */ { 1, 1, 1, 1 },
4150 /* STOPPED */ { 1, 1, 0, 1 },
4151 /* PAUSED */ { 1, 1, 0, 1 },
4153 static const MFCLOCK_STATE states[CLOCK_CMD_MAX] =
4155 /* CLOCK_CMD_START */ MFCLOCK_STATE_RUNNING,
4156 /* CLOCK_CMD_STOP */ MFCLOCK_STATE_STOPPED,
4157 /* CLOCK_CMD_PAUSE */ MFCLOCK_STATE_PAUSED,
4158 /* CLOCK_CMD_SET_RATE */ 0, /* Unused */
4160 static const enum clock_notification notifications[CLOCK_CMD_MAX] =
4162 /* CLOCK_CMD_START */ CLOCK_NOTIFY_START,
4163 /* CLOCK_CMD_STOP */ CLOCK_NOTIFY_STOP,
4164 /* CLOCK_CMD_PAUSE */ CLOCK_NOTIFY_PAUSE,
4165 /* CLOCK_CMD_SET_RATE */ CLOCK_NOTIFY_SET_RATE,
4167 enum clock_notification notification;
4168 struct clock_sink *sink;
4169 MFCLOCK_STATE old_state;
4170 IMFAsyncResult *result;
4171 MFTIME system_time;
4172 HRESULT hr;
4174 if (!clock->time_source)
4175 return MF_E_CLOCK_NO_TIME_SOURCE;
4177 if (command != CLOCK_CMD_SET_RATE && clock->state == states[command] && clock->state != MFCLOCK_STATE_RUNNING)
4178 return MF_E_CLOCK_STATE_ALREADY_SET;
4180 if (!state_change_is_allowed[clock->state][command])
4181 return MF_E_INVALIDREQUEST;
4183 system_time = MFGetSystemTime();
4185 if (command == CLOCK_CMD_START && clock->state == MFCLOCK_STATE_PAUSED &&
4186 param.u.offset == PRESENTATION_CURRENT_POSITION)
4188 notification = CLOCK_NOTIFY_RESTART;
4190 else
4191 notification = notifications[command];
4193 if (FAILED(hr = clock_call_state_change(system_time, param, notification, clock->time_source_sink)))
4194 return hr;
4196 old_state = clock->state;
4197 if (command != CLOCK_CMD_SET_RATE)
4198 clock->state = states[command];
4200 /* Dump all pending timer requests immediately on start; otherwise try to cancel scheduled items when
4201 transitioning from running state. */
4202 if ((clock->state == MFCLOCK_STATE_RUNNING) ^ (old_state == MFCLOCK_STATE_RUNNING))
4204 struct clock_timer *timer, *timer2;
4206 if (clock->state == MFCLOCK_STATE_RUNNING)
4208 LIST_FOR_EACH_ENTRY_SAFE(timer, timer2, &clock->timers, struct clock_timer, entry)
4210 list_remove(&timer->entry);
4211 hr = MFCreateAsyncResult(&timer->IUnknown_iface, &clock->timer_callback, NULL, &result);
4212 IUnknown_Release(&timer->IUnknown_iface);
4213 if (SUCCEEDED(hr))
4215 MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_TIMER, result);
4216 IMFAsyncResult_Release(result);
4220 else
4222 LIST_FOR_EACH_ENTRY(timer, &clock->timers, struct clock_timer, entry)
4224 if (timer->key)
4226 MFCancelWorkItem(timer->key);
4227 timer->key = 0;
4233 LIST_FOR_EACH_ENTRY(sink, &clock->sinks, struct clock_sink, entry)
4235 clock_notify_async_sink(clock, system_time, param, notification, sink->state_sink);
4238 return S_OK;
4241 static HRESULT WINAPI present_clock_Start(IMFPresentationClock *iface, LONGLONG start_offset)
4243 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
4244 struct clock_state_change_param param = {{0}};
4245 HRESULT hr;
4247 TRACE("%p, %s.\n", iface, debugstr_time(start_offset));
4249 EnterCriticalSection(&clock->cs);
4250 clock->start_offset = param.u.offset = start_offset;
4251 hr = clock_change_state(clock, CLOCK_CMD_START, param);
4252 LeaveCriticalSection(&clock->cs);
4254 return hr;
4257 static HRESULT WINAPI present_clock_Stop(IMFPresentationClock *iface)
4259 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
4260 struct clock_state_change_param param = {{0}};
4261 HRESULT hr;
4263 TRACE("%p.\n", iface);
4265 EnterCriticalSection(&clock->cs);
4266 hr = clock_change_state(clock, CLOCK_CMD_STOP, param);
4267 LeaveCriticalSection(&clock->cs);
4269 return hr;
4272 static HRESULT WINAPI present_clock_Pause(IMFPresentationClock *iface)
4274 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
4275 struct clock_state_change_param param = {{0}};
4276 HRESULT hr;
4278 TRACE("%p.\n", iface);
4280 EnterCriticalSection(&clock->cs);
4281 hr = clock_change_state(clock, CLOCK_CMD_PAUSE, param);
4282 LeaveCriticalSection(&clock->cs);
4284 return hr;
4287 static const IMFPresentationClockVtbl presentationclockvtbl =
4289 present_clock_QueryInterface,
4290 present_clock_AddRef,
4291 present_clock_Release,
4292 present_clock_GetClockCharacteristics,
4293 present_clock_GetCorrelatedTime,
4294 present_clock_GetContinuityKey,
4295 present_clock_GetState,
4296 present_clock_GetProperties,
4297 present_clock_SetTimeSource,
4298 present_clock_GetTimeSource,
4299 present_clock_GetTime,
4300 present_clock_AddClockStateSink,
4301 present_clock_RemoveClockStateSink,
4302 present_clock_Start,
4303 present_clock_Stop,
4304 present_clock_Pause,
4307 static HRESULT WINAPI present_clock_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **out)
4309 struct presentation_clock *clock = impl_from_IMFRateControl(iface);
4310 return IMFPresentationClock_QueryInterface(&clock->IMFPresentationClock_iface, riid, out);
4313 static ULONG WINAPI present_clock_rate_control_AddRef(IMFRateControl *iface)
4315 struct presentation_clock *clock = impl_from_IMFRateControl(iface);
4316 return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
4319 static ULONG WINAPI present_clock_rate_control_Release(IMFRateControl *iface)
4321 struct presentation_clock *clock = impl_from_IMFRateControl(iface);
4322 return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
4325 static HRESULT WINAPI present_clock_rate_SetRate(IMFRateControl *iface, BOOL thin, float rate)
4327 struct presentation_clock *clock = impl_from_IMFRateControl(iface);
4328 struct clock_state_change_param param;
4329 HRESULT hr;
4331 TRACE("%p, %d, %f.\n", iface, thin, rate);
4333 if (thin)
4334 return MF_E_THINNING_UNSUPPORTED;
4336 EnterCriticalSection(&clock->cs);
4337 param.u.rate = rate;
4338 if (SUCCEEDED(hr = clock_change_state(clock, CLOCK_CMD_SET_RATE, param)))
4339 clock->rate = rate;
4340 LeaveCriticalSection(&clock->cs);
4342 return hr;
4345 static HRESULT WINAPI present_clock_rate_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
4347 struct presentation_clock *clock = impl_from_IMFRateControl(iface);
4349 TRACE("%p, %p, %p.\n", iface, thin, rate);
4351 if (!rate)
4352 return E_INVALIDARG;
4354 if (thin)
4355 *thin = FALSE;
4357 EnterCriticalSection(&clock->cs);
4358 *rate = clock->rate;
4359 LeaveCriticalSection(&clock->cs);
4361 return S_OK;
4364 static const IMFRateControlVtbl presentclockratecontrolvtbl =
4366 present_clock_rate_control_QueryInterface,
4367 present_clock_rate_control_AddRef,
4368 present_clock_rate_control_Release,
4369 present_clock_rate_SetRate,
4370 present_clock_rate_GetRate,
4373 static HRESULT WINAPI present_clock_timer_QueryInterface(IMFTimer *iface, REFIID riid, void **out)
4375 struct presentation_clock *clock = impl_from_IMFTimer(iface);
4376 return IMFPresentationClock_QueryInterface(&clock->IMFPresentationClock_iface, riid, out);
4379 static ULONG WINAPI present_clock_timer_AddRef(IMFTimer *iface)
4381 struct presentation_clock *clock = impl_from_IMFTimer(iface);
4382 return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
4385 static ULONG WINAPI present_clock_timer_Release(IMFTimer *iface)
4387 struct presentation_clock *clock = impl_from_IMFTimer(iface);
4388 return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
4391 static HRESULT present_clock_schedule_timer(struct presentation_clock *clock, DWORD flags, LONGLONG time,
4392 struct clock_timer *timer)
4394 IMFAsyncResult *result;
4395 MFTIME systime, clocktime;
4396 LONGLONG frequency;
4397 HRESULT hr;
4399 if (!(flags & MFTIMER_RELATIVE))
4401 if (FAILED(hr = IMFPresentationTimeSource_GetCorrelatedTime(clock->time_source, 0, &clocktime, &systime)))
4403 WARN("Failed to get clock time, hr %#x.\n", hr);
4404 return hr;
4406 time -= clocktime;
4409 frequency = clock->frequency / 1000;
4410 time /= frequency;
4412 /* Scheduled item is using clock instance callback, with timer instance as an object. Clock callback will
4413 call user callback and cleanup timer list. */
4415 if (FAILED(hr = MFCreateAsyncResult(&timer->IUnknown_iface, &clock->timer_callback, NULL, &result)))
4416 return hr;
4418 hr = MFScheduleWorkItemEx(result, -time, &timer->key);
4419 IMFAsyncResult_Release(result);
4421 return hr;
4424 static HRESULT WINAPI clock_timer_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
4426 if (IsEqualIID(riid, &IID_IUnknown))
4428 *obj = iface;
4429 IUnknown_AddRef(iface);
4430 return S_OK;
4433 *obj = NULL;
4434 return E_NOINTERFACE;
4437 static ULONG WINAPI clock_timer_AddRef(IUnknown *iface)
4439 struct clock_timer *timer = impl_clock_timer_from_IUnknown(iface);
4440 return InterlockedIncrement(&timer->refcount);
4443 static ULONG WINAPI clock_timer_Release(IUnknown *iface)
4445 struct clock_timer *timer = impl_clock_timer_from_IUnknown(iface);
4446 ULONG refcount = InterlockedDecrement(&timer->refcount);
4448 if (!refcount)
4450 IMFAsyncResult_Release(timer->result);
4451 IMFAsyncCallback_Release(timer->callback);
4452 heap_free(timer);
4455 return refcount;
4458 static const IUnknownVtbl clock_timer_vtbl =
4460 clock_timer_QueryInterface,
4461 clock_timer_AddRef,
4462 clock_timer_Release,
4465 static HRESULT WINAPI present_clock_timer_SetTimer(IMFTimer *iface, DWORD flags, LONGLONG time,
4466 IMFAsyncCallback *callback, IUnknown *state, IUnknown **cancel_key)
4468 struct presentation_clock *clock = impl_from_IMFTimer(iface);
4469 struct clock_timer *clock_timer;
4470 HRESULT hr;
4472 TRACE("%p, %#x, %s, %p, %p, %p.\n", iface, flags, debugstr_time(time), callback, state, cancel_key);
4474 if (!(clock_timer = heap_alloc_zero(sizeof(*clock_timer))))
4475 return E_OUTOFMEMORY;
4477 if (FAILED(hr = MFCreateAsyncResult(NULL, NULL, state, &clock_timer->result)))
4479 heap_free(clock_timer);
4480 return hr;
4483 clock_timer->IUnknown_iface.lpVtbl = &clock_timer_vtbl;
4484 clock_timer->refcount = 1;
4485 clock_timer->callback = callback;
4486 IMFAsyncCallback_AddRef(clock_timer->callback);
4488 EnterCriticalSection(&clock->cs);
4490 if (clock->state == MFCLOCK_STATE_RUNNING)
4491 hr = present_clock_schedule_timer(clock, flags, time, clock_timer);
4492 else if (clock->state == MFCLOCK_STATE_STOPPED)
4493 hr = MF_S_CLOCK_STOPPED;
4495 if (SUCCEEDED(hr))
4497 list_add_tail(&clock->timers, &clock_timer->entry);
4498 if (cancel_key)
4500 *cancel_key = &clock_timer->IUnknown_iface;
4501 IUnknown_AddRef(*cancel_key);
4505 LeaveCriticalSection(&clock->cs);
4507 if (FAILED(hr))
4508 IUnknown_Release(&clock_timer->IUnknown_iface);
4510 return hr;
4513 static HRESULT WINAPI present_clock_timer_CancelTimer(IMFTimer *iface, IUnknown *cancel_key)
4515 struct presentation_clock *clock = impl_from_IMFTimer(iface);
4516 struct clock_timer *timer;
4518 TRACE("%p, %p.\n", iface, cancel_key);
4520 EnterCriticalSection(&clock->cs);
4522 LIST_FOR_EACH_ENTRY(timer, &clock->timers, struct clock_timer, entry)
4524 if (&timer->IUnknown_iface == cancel_key)
4526 list_remove(&timer->entry);
4527 if (timer->key)
4529 MFCancelWorkItem(timer->key);
4530 timer->key = 0;
4532 IUnknown_Release(&timer->IUnknown_iface);
4533 break;
4537 LeaveCriticalSection(&clock->cs);
4539 return S_OK;
4542 static const IMFTimerVtbl presentclocktimervtbl =
4544 present_clock_timer_QueryInterface,
4545 present_clock_timer_AddRef,
4546 present_clock_timer_Release,
4547 present_clock_timer_SetTimer,
4548 present_clock_timer_CancelTimer,
4551 static HRESULT WINAPI present_clock_shutdown_QueryInterface(IMFShutdown *iface, REFIID riid, void **out)
4553 struct presentation_clock *clock = impl_from_IMFShutdown(iface);
4554 return IMFPresentationClock_QueryInterface(&clock->IMFPresentationClock_iface, riid, out);
4557 static ULONG WINAPI present_clock_shutdown_AddRef(IMFShutdown *iface)
4559 struct presentation_clock *clock = impl_from_IMFShutdown(iface);
4560 return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
4563 static ULONG WINAPI present_clock_shutdown_Release(IMFShutdown *iface)
4565 struct presentation_clock *clock = impl_from_IMFShutdown(iface);
4566 return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
4569 static HRESULT WINAPI present_clock_shutdown_Shutdown(IMFShutdown *iface)
4571 struct presentation_clock *clock = impl_from_IMFShutdown(iface);
4573 TRACE("%p.\n", iface);
4575 EnterCriticalSection(&clock->cs);
4576 clock->is_shut_down = TRUE;
4577 LeaveCriticalSection(&clock->cs);
4579 return S_OK;
4582 static HRESULT WINAPI present_clock_shutdown_GetShutdownStatus(IMFShutdown *iface, MFSHUTDOWN_STATUS *status)
4584 struct presentation_clock *clock = impl_from_IMFShutdown(iface);
4585 HRESULT hr = S_OK;
4587 TRACE("%p, %p.\n", iface, status);
4589 if (!status)
4590 return E_INVALIDARG;
4592 EnterCriticalSection(&clock->cs);
4593 if (clock->is_shut_down)
4594 *status = MFSHUTDOWN_COMPLETED;
4595 else
4596 hr = MF_E_INVALIDREQUEST;
4597 LeaveCriticalSection(&clock->cs);
4599 return hr;
4602 static const IMFShutdownVtbl presentclockshutdownvtbl =
4604 present_clock_shutdown_QueryInterface,
4605 present_clock_shutdown_AddRef,
4606 present_clock_shutdown_Release,
4607 present_clock_shutdown_Shutdown,
4608 present_clock_shutdown_GetShutdownStatus,
4611 static HRESULT WINAPI present_clock_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **out)
4613 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
4614 IsEqualIID(riid, &IID_IUnknown))
4616 *out = iface;
4617 IMFAsyncCallback_AddRef(iface);
4618 return S_OK;
4621 WARN("Unsupported %s.\n", wine_dbgstr_guid(riid));
4622 *out = NULL;
4623 return E_NOINTERFACE;
4626 static ULONG WINAPI present_clock_sink_callback_AddRef(IMFAsyncCallback *iface)
4628 struct presentation_clock *clock = impl_from_sink_callback_IMFAsyncCallback(iface);
4629 return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
4632 static ULONG WINAPI present_clock_sink_callback_Release(IMFAsyncCallback *iface)
4634 struct presentation_clock *clock = impl_from_sink_callback_IMFAsyncCallback(iface);
4635 return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
4638 static HRESULT WINAPI present_clock_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
4640 return E_NOTIMPL;
4643 static HRESULT WINAPI present_clock_sink_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
4645 struct sink_notification *data;
4646 IUnknown *object;
4647 HRESULT hr;
4649 if (FAILED(hr = IMFAsyncResult_GetObject(result, &object)))
4650 return hr;
4652 data = impl_sink_notification_from_IUnknown(object);
4654 clock_call_state_change(data->system_time, data->param, data->notification, data->sink);
4656 IUnknown_Release(object);
4658 return S_OK;
4661 static const IMFAsyncCallbackVtbl presentclocksinkcallbackvtbl =
4663 present_clock_callback_QueryInterface,
4664 present_clock_sink_callback_AddRef,
4665 present_clock_sink_callback_Release,
4666 present_clock_callback_GetParameters,
4667 present_clock_sink_callback_Invoke,
4670 static ULONG WINAPI present_clock_timer_callback_AddRef(IMFAsyncCallback *iface)
4672 struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface);
4673 return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
4676 static ULONG WINAPI present_clock_timer_callback_Release(IMFAsyncCallback *iface)
4678 struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface);
4679 return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
4682 static HRESULT WINAPI present_clock_timer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
4684 struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface);
4685 struct clock_timer *timer;
4686 IUnknown *object;
4687 HRESULT hr;
4689 if (FAILED(hr = IMFAsyncResult_GetObject(result, &object)))
4690 return hr;
4692 timer = impl_clock_timer_from_IUnknown(object);
4694 EnterCriticalSection(&clock->cs);
4695 list_remove(&timer->entry);
4696 IUnknown_Release(&timer->IUnknown_iface);
4697 LeaveCriticalSection(&clock->cs);
4699 IMFAsyncCallback_Invoke(timer->callback, timer->result);
4701 IUnknown_Release(object);
4703 return S_OK;
4706 static const IMFAsyncCallbackVtbl presentclocktimercallbackvtbl =
4708 present_clock_callback_QueryInterface,
4709 present_clock_timer_callback_AddRef,
4710 present_clock_timer_callback_Release,
4711 present_clock_callback_GetParameters,
4712 present_clock_timer_callback_Invoke,
4715 /***********************************************************************
4716 * MFCreatePresentationClock (mf.@)
4718 HRESULT WINAPI MFCreatePresentationClock(IMFPresentationClock **clock)
4720 struct presentation_clock *object;
4722 TRACE("%p.\n", clock);
4724 object = heap_alloc_zero(sizeof(*object));
4725 if (!object)
4726 return E_OUTOFMEMORY;
4728 object->IMFPresentationClock_iface.lpVtbl = &presentationclockvtbl;
4729 object->IMFRateControl_iface.lpVtbl = &presentclockratecontrolvtbl;
4730 object->IMFTimer_iface.lpVtbl = &presentclocktimervtbl;
4731 object->IMFShutdown_iface.lpVtbl = &presentclockshutdownvtbl;
4732 object->sink_callback.lpVtbl = &presentclocksinkcallbackvtbl;
4733 object->timer_callback.lpVtbl = &presentclocktimercallbackvtbl;
4734 object->refcount = 1;
4735 list_init(&object->sinks);
4736 list_init(&object->timers);
4737 object->rate = 1.0f;
4738 InitializeCriticalSection(&object->cs);
4740 *clock = &object->IMFPresentationClock_iface;
4742 return S_OK;
4745 static HRESULT WINAPI standard_quality_manager_QueryInterface(IMFQualityManager *iface, REFIID riid, void **out)
4747 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
4749 if (IsEqualIID(riid, &IID_IMFQualityManager) ||
4750 IsEqualIID(riid, &IID_IUnknown))
4752 *out = iface;
4753 IMFQualityManager_AddRef(iface);
4754 return S_OK;
4757 WARN("Unsupported %s.\n", debugstr_guid(riid));
4758 *out = NULL;
4759 return E_NOINTERFACE;
4762 static ULONG WINAPI standard_quality_manager_AddRef(IMFQualityManager *iface)
4764 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
4765 ULONG refcount = InterlockedIncrement(&manager->refcount);
4767 TRACE("%p, refcount %u.\n", iface, refcount);
4769 return refcount;
4772 static ULONG WINAPI standard_quality_manager_Release(IMFQualityManager *iface)
4774 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
4775 ULONG refcount = InterlockedDecrement(&manager->refcount);
4777 TRACE("%p, refcount %u.\n", iface, refcount);
4779 if (!refcount)
4781 if (manager->clock)
4782 IMFPresentationClock_Release(manager->clock);
4783 DeleteCriticalSection(&manager->cs);
4784 heap_free(manager);
4787 return refcount;
4790 static HRESULT WINAPI standard_quality_manager_NotifyTopology(IMFQualityManager *iface, IMFTopology *topology)
4792 FIXME("%p, %p stub.\n", iface, topology);
4794 return S_OK;
4797 static HRESULT WINAPI standard_quality_manager_NotifyPresentationClock(IMFQualityManager *iface,
4798 IMFPresentationClock *clock)
4800 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
4802 TRACE("%p, %p.\n", iface, clock);
4804 if (!clock)
4805 return E_POINTER;
4807 EnterCriticalSection(&manager->cs);
4808 if (manager->clock)
4809 IMFPresentationClock_Release(manager->clock);
4810 manager->clock = clock;
4811 IMFPresentationClock_AddRef(manager->clock);
4812 LeaveCriticalSection(&manager->cs);
4814 return S_OK;
4817 static HRESULT WINAPI standard_quality_manager_NotifyProcessInput(IMFQualityManager *iface, IMFTopologyNode *node,
4818 LONG input_index, IMFSample *sample)
4820 TRACE("%p, %p, %d, %p stub.\n", iface, node, input_index, sample);
4822 return E_NOTIMPL;
4825 static HRESULT WINAPI standard_quality_manager_NotifyProcessOutput(IMFQualityManager *iface, IMFTopologyNode *node,
4826 LONG output_index, IMFSample *sample)
4828 TRACE("%p, %p, %d, %p stub.\n", iface, node, output_index, sample);
4830 return E_NOTIMPL;
4833 static HRESULT WINAPI standard_quality_manager_NotifyQualityEvent(IMFQualityManager *iface, IUnknown *object,
4834 IMFMediaEvent *event)
4836 FIXME("%p, %p, %p stub.\n", iface, object, event);
4838 return E_NOTIMPL;
4841 static HRESULT WINAPI standard_quality_manager_Shutdown(IMFQualityManager *iface)
4843 FIXME("%p stub.\n", iface);
4845 return E_NOTIMPL;
4848 static IMFQualityManagerVtbl standard_quality_manager_vtbl =
4850 standard_quality_manager_QueryInterface,
4851 standard_quality_manager_AddRef,
4852 standard_quality_manager_Release,
4853 standard_quality_manager_NotifyTopology,
4854 standard_quality_manager_NotifyPresentationClock,
4855 standard_quality_manager_NotifyProcessInput,
4856 standard_quality_manager_NotifyProcessOutput,
4857 standard_quality_manager_NotifyQualityEvent,
4858 standard_quality_manager_Shutdown,
4861 HRESULT WINAPI MFCreateStandardQualityManager(IMFQualityManager **manager)
4863 struct quality_manager *object;
4865 TRACE("%p.\n", manager);
4867 object = heap_alloc_zero(sizeof(*object));
4868 if (!object)
4869 return E_OUTOFMEMORY;
4871 object->IMFQualityManager_iface.lpVtbl = &standard_quality_manager_vtbl;
4872 object->refcount = 1;
4873 InitializeCriticalSection(&object->cs);
4875 *manager = &object->IMFQualityManager_iface;
4877 return S_OK;