mf/session: Shutdown and release presentation clock on session shutdown.
[wine.git] / dlls / mf / session.c
blob4821ed5c90a37045b6122f0a3c3a008cbe53c31c
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 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
37 enum session_command
39 SESSION_CMD_CLEAR_TOPOLOGIES,
40 SESSION_CMD_CLOSE,
41 SESSION_CMD_SET_TOPOLOGY,
42 SESSION_CMD_START,
43 SESSION_CMD_PAUSE,
44 SESSION_CMD_STOP,
45 /* Internally used commands. */
46 SESSION_CMD_END,
47 SESSION_CMD_QM_NOTIFY_TOPOLOGY,
48 SESSION_CMD_SA_READY,
51 struct session_op
53 IUnknown IUnknown_iface;
54 LONG refcount;
55 enum session_command command;
56 union
58 struct
60 DWORD flags;
61 IMFTopology *topology;
62 } set_topology;
63 struct
65 GUID time_format;
66 PROPVARIANT start_position;
67 } start;
68 struct
70 IMFTopology *topology;
71 } notify_topology;
72 struct
74 TOPOID node_id;
75 } sa_ready;
76 } u;
77 struct list entry;
80 struct queued_topology
82 struct list entry;
83 IMFTopology *topology;
84 MF_TOPOSTATUS status;
87 enum session_state
89 SESSION_STATE_STOPPED = 0,
90 SESSION_STATE_STARTING_SOURCES,
91 SESSION_STATE_PREROLLING_SINKS,
92 SESSION_STATE_STARTING_SINKS,
93 SESSION_STATE_STARTED,
94 SESSION_STATE_PAUSING_SINKS,
95 SESSION_STATE_PAUSING_SOURCES,
96 SESSION_STATE_PAUSED,
97 SESSION_STATE_STOPPING_SINKS,
98 SESSION_STATE_STOPPING_SOURCES,
99 SESSION_STATE_FINALIZING_SINKS,
100 SESSION_STATE_CLOSED,
101 SESSION_STATE_SHUT_DOWN,
104 enum object_state
106 OBJ_STATE_STOPPED = 0,
107 OBJ_STATE_STARTED,
108 OBJ_STATE_PAUSED,
109 OBJ_STATE_PREROLLED,
110 OBJ_STATE_INVALID,
113 enum media_source_flags
115 SOURCE_FLAG_END_OF_PRESENTATION = 0x1,
118 struct media_source
120 struct list entry;
121 IMFMediaSource *source;
122 IMFPresentationDescriptor *pd;
123 enum object_state state;
124 unsigned int flags;
127 struct media_sink
129 struct list entry;
130 IMFMediaSink *sink;
131 IMFMediaSinkPreroll *preroll;
132 IMFMediaEventGenerator *event_generator;
133 BOOL finalized;
136 struct sample
138 struct list entry;
139 IMFSample *sample;
142 struct transform_stream
144 struct list samples;
145 unsigned int requests;
148 enum topo_node_flags
150 TOPO_NODE_END_OF_STREAM = 0x1,
153 struct topo_node
155 struct list entry;
156 struct media_session *session;
157 MF_TOPOLOGY_TYPE type;
158 TOPOID node_id;
159 IMFTopologyNode *node;
160 enum object_state state;
161 unsigned int flags;
162 union
164 IMFMediaStream *source_stream;
165 IMFStreamSink *sink_stream;
166 IMFTransform *transform;
167 IUnknown *object;
168 } object;
170 union
172 struct
174 IMFMediaSource *source;
175 unsigned int stream_id;
176 } source;
177 struct
179 unsigned int requests;
180 IMFVideoSampleAllocatorNotify notify_cb;
181 IMFVideoSampleAllocator *allocator;
182 IMFVideoSampleAllocatorCallback *allocator_cb;
183 } sink;
184 struct
186 struct transform_stream *inputs;
187 unsigned int *input_map;
188 unsigned int input_count;
190 struct transform_stream *outputs;
191 unsigned int *output_map;
192 unsigned int output_count;
193 } transform;
194 } u;
197 enum presentation_flags
199 SESSION_FLAG_SOURCES_SUBSCRIBED = 0x1,
200 SESSION_FLAG_PRESENTATION_CLOCK_SET = 0x2,
201 SESSION_FLAG_FINALIZE_SINKS = 0x4,
202 SESSION_FLAG_NEEDS_PREROLL = 0x8,
203 SESSION_FLAG_END_OF_PRESENTATION = 0x10,
206 struct media_session
208 IMFMediaSession IMFMediaSession_iface;
209 IMFGetService IMFGetService_iface;
210 IMFRateSupport IMFRateSupport_iface;
211 IMFRateControl IMFRateControl_iface;
212 IMFAsyncCallback commands_callback;
213 IMFAsyncCallback events_callback;
214 IMFAsyncCallback sink_finalizer_callback;
215 LONG refcount;
216 IMFMediaEventQueue *event_queue;
217 IMFPresentationClock *clock;
218 IMFPresentationTimeSource *system_time_source;
219 IMFRateControl *clock_rate_control;
220 IMFTopoLoader *topo_loader;
221 IMFQualityManager *quality_manager;
222 struct
224 IMFTopology *current_topology;
225 MF_TOPOSTATUS topo_status;
226 MFTIME clock_stop_time;
227 unsigned int flags;
228 struct list sources;
229 struct list sinks;
230 struct list nodes;
232 /* Latest Start() arguments. */
233 GUID time_format;
234 PROPVARIANT start_position;
235 } presentation;
236 struct list topologies;
237 struct list commands;
238 enum session_state state;
239 DWORD caps;
240 CRITICAL_SECTION cs;
243 struct clock_sink
245 struct list entry;
246 IMFClockStateSink *state_sink;
249 enum clock_command
251 CLOCK_CMD_START = 0,
252 CLOCK_CMD_STOP,
253 CLOCK_CMD_PAUSE,
254 CLOCK_CMD_SET_RATE,
255 CLOCK_CMD_MAX,
258 enum clock_notification
260 CLOCK_NOTIFY_START,
261 CLOCK_NOTIFY_STOP,
262 CLOCK_NOTIFY_PAUSE,
263 CLOCK_NOTIFY_RESTART,
264 CLOCK_NOTIFY_SET_RATE,
267 struct clock_state_change_param
269 union
271 LONGLONG offset;
272 float rate;
273 } u;
276 struct sink_notification
278 IUnknown IUnknown_iface;
279 LONG refcount;
280 MFTIME system_time;
281 struct clock_state_change_param param;
282 enum clock_notification notification;
283 IMFClockStateSink *sink;
286 struct clock_timer
288 IUnknown IUnknown_iface;
289 LONG refcount;
290 IMFAsyncResult *result;
291 IMFAsyncCallback *callback;
292 MFWORKITEM_KEY key;
293 struct list entry;
296 struct presentation_clock
298 IMFPresentationClock IMFPresentationClock_iface;
299 IMFRateControl IMFRateControl_iface;
300 IMFTimer IMFTimer_iface;
301 IMFShutdown IMFShutdown_iface;
302 IMFAsyncCallback sink_callback;
303 IMFAsyncCallback timer_callback;
304 LONG refcount;
305 IMFPresentationTimeSource *time_source;
306 IMFClockStateSink *time_source_sink;
307 MFCLOCK_STATE state;
308 LONGLONG start_offset;
309 struct list sinks;
310 struct list timers;
311 float rate;
312 LONGLONG frequency;
313 CRITICAL_SECTION cs;
314 BOOL is_shut_down;
317 struct quality_manager
319 IMFQualityManager IMFQualityManager_iface;
320 LONG refcount;
322 IMFPresentationClock *clock;
323 CRITICAL_SECTION cs;
326 static inline struct media_session *impl_from_IMFMediaSession(IMFMediaSession *iface)
328 return CONTAINING_RECORD(iface, struct media_session, IMFMediaSession_iface);
331 static struct media_session *impl_from_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
333 return CONTAINING_RECORD(iface, struct media_session, commands_callback);
336 static struct media_session *impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
338 return CONTAINING_RECORD(iface, struct media_session, events_callback);
341 static struct media_session *impl_from_sink_finalizer_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
343 return CONTAINING_RECORD(iface, struct media_session, sink_finalizer_callback);
346 static struct media_session *impl_from_IMFGetService(IMFGetService *iface)
348 return CONTAINING_RECORD(iface, struct media_session, IMFGetService_iface);
351 static struct media_session *impl_session_from_IMFRateSupport(IMFRateSupport *iface)
353 return CONTAINING_RECORD(iface, struct media_session, IMFRateSupport_iface);
356 static struct media_session *impl_session_from_IMFRateControl(IMFRateControl *iface)
358 return CONTAINING_RECORD(iface, struct media_session, IMFRateControl_iface);
361 static struct session_op *impl_op_from_IUnknown(IUnknown *iface)
363 return CONTAINING_RECORD(iface, struct session_op, IUnknown_iface);
366 static struct presentation_clock *impl_from_IMFPresentationClock(IMFPresentationClock *iface)
368 return CONTAINING_RECORD(iface, struct presentation_clock, IMFPresentationClock_iface);
371 static struct presentation_clock *impl_from_IMFRateControl(IMFRateControl *iface)
373 return CONTAINING_RECORD(iface, struct presentation_clock, IMFRateControl_iface);
376 static struct presentation_clock *impl_from_IMFTimer(IMFTimer *iface)
378 return CONTAINING_RECORD(iface, struct presentation_clock, IMFTimer_iface);
381 static struct presentation_clock *impl_from_IMFShutdown(IMFShutdown *iface)
383 return CONTAINING_RECORD(iface, struct presentation_clock, IMFShutdown_iface);
386 static struct presentation_clock *impl_from_sink_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
388 return CONTAINING_RECORD(iface, struct presentation_clock, sink_callback);
391 static struct presentation_clock *impl_from_timer_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
393 return CONTAINING_RECORD(iface, struct presentation_clock, timer_callback);
396 static struct clock_timer *impl_clock_timer_from_IUnknown(IUnknown *iface)
398 return CONTAINING_RECORD(iface, struct clock_timer, IUnknown_iface);
401 static struct sink_notification *impl_sink_notification_from_IUnknown(IUnknown *iface)
403 return CONTAINING_RECORD(iface, struct sink_notification, IUnknown_iface);
406 static struct quality_manager *impl_from_IMFQualityManager(IMFQualityManager *iface)
408 return CONTAINING_RECORD(iface, struct quality_manager, IMFQualityManager_iface);
411 static struct topo_node *impl_node_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify *iface)
413 return CONTAINING_RECORD(iface, struct topo_node, u.sink.notify_cb);
416 /* IMFLocalMFTRegistration */
417 static HRESULT WINAPI local_mft_registration_QueryInterface(IMFLocalMFTRegistration *iface, REFIID riid, void **obj)
419 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
421 if (IsEqualIID(riid, &IID_IMFLocalMFTRegistration) ||
422 IsEqualIID(riid, &IID_IUnknown))
424 *obj = iface;
425 IMFLocalMFTRegistration_AddRef(iface);
426 return S_OK;
429 WARN("Unexpected %s.\n", debugstr_guid(riid));
430 *obj = NULL;
431 return E_NOINTERFACE;
434 static ULONG WINAPI local_mft_registration_AddRef(IMFLocalMFTRegistration *iface)
436 return 2;
439 static ULONG WINAPI local_mft_registration_Release(IMFLocalMFTRegistration *iface)
441 return 1;
444 static HRESULT WINAPI local_mft_registration_RegisterMFTs(IMFLocalMFTRegistration *iface, MFT_REGISTRATION_INFO *info,
445 DWORD count)
447 HRESULT hr = S_OK;
448 DWORD i;
450 TRACE("%p, %p, %u.\n", iface, info, count);
452 for (i = 0; i < count; ++i)
454 if (FAILED(hr = MFTRegisterLocalByCLSID(&info[i].clsid, &info[i].guidCategory, info[i].pszName,
455 info[i].uiFlags, info[i].cInTypes, info[i].pInTypes, info[i].cOutTypes, info[i].pOutTypes)))
457 break;
461 return hr;
464 static const IMFLocalMFTRegistrationVtbl local_mft_registration_vtbl =
466 local_mft_registration_QueryInterface,
467 local_mft_registration_AddRef,
468 local_mft_registration_Release,
469 local_mft_registration_RegisterMFTs,
472 static IMFLocalMFTRegistration local_mft_registration = { &local_mft_registration_vtbl };
474 static HRESULT WINAPI session_op_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
476 if (IsEqualIID(riid, &IID_IUnknown))
478 *obj = iface;
479 IUnknown_AddRef(iface);
480 return S_OK;
483 *obj = NULL;
484 return E_NOINTERFACE;
487 static ULONG WINAPI session_op_AddRef(IUnknown *iface)
489 struct session_op *op = impl_op_from_IUnknown(iface);
490 ULONG refcount = InterlockedIncrement(&op->refcount);
492 TRACE("%p, refcount %u.\n", iface, refcount);
494 return refcount;
497 static ULONG WINAPI session_op_Release(IUnknown *iface)
499 struct session_op *op = impl_op_from_IUnknown(iface);
500 ULONG refcount = InterlockedDecrement(&op->refcount);
502 TRACE("%p, refcount %u.\n", iface, refcount);
504 if (!refcount)
506 switch (op->command)
508 case SESSION_CMD_SET_TOPOLOGY:
509 if (op->u.set_topology.topology)
510 IMFTopology_Release(op->u.set_topology.topology);
511 break;
512 case SESSION_CMD_START:
513 PropVariantClear(&op->u.start.start_position);
514 break;
515 case SESSION_CMD_QM_NOTIFY_TOPOLOGY:
516 if (op->u.notify_topology.topology)
517 IMFTopology_Release(op->u.notify_topology.topology);
518 break;
519 default:
522 heap_free(op);
525 return refcount;
528 static IUnknownVtbl session_op_vtbl =
530 session_op_QueryInterface,
531 session_op_AddRef,
532 session_op_Release,
535 static HRESULT create_session_op(enum session_command command, struct session_op **ret)
537 struct session_op *op;
539 if (!(op = heap_alloc_zero(sizeof(*op))))
540 return E_OUTOFMEMORY;
542 op->IUnknown_iface.lpVtbl = &session_op_vtbl;
543 op->refcount = 1;
544 op->command = command;
546 *ret = op;
548 return S_OK;
551 static HRESULT session_is_shut_down(struct media_session *session)
553 return session->state == SESSION_STATE_SHUT_DOWN ? MF_E_SHUTDOWN : S_OK;
556 static void session_push_back_command(struct media_session *session, enum session_command command)
558 struct session_op *op;
560 if (SUCCEEDED(create_session_op(command, &op)))
561 list_add_head(&session->commands, &op->entry);
564 static HRESULT session_submit_command(struct media_session *session, struct session_op *op)
566 HRESULT hr;
568 EnterCriticalSection(&session->cs);
569 if (SUCCEEDED(hr = session_is_shut_down(session)))
571 if (list_empty(&session->commands))
572 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface);
573 list_add_tail(&session->commands, &op->entry);
574 IUnknown_AddRef(&op->IUnknown_iface);
576 LeaveCriticalSection(&session->cs);
578 return hr;
581 static HRESULT session_submit_simple_command(struct media_session *session, enum session_command command)
583 struct session_op *op;
584 HRESULT hr;
586 if (FAILED(hr = create_session_op(command, &op)))
587 return hr;
589 hr = session_submit_command(session, op);
590 IUnknown_Release(&op->IUnknown_iface);
591 return hr;
594 static void session_clear_topologies(struct media_session *session)
596 struct queued_topology *ptr, *next;
598 LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &session->topologies, struct queued_topology, entry)
600 list_remove(&ptr->entry);
601 IMFTopology_Release(ptr->topology);
602 heap_free(ptr);
606 static void session_set_topo_status(struct media_session *session, HRESULT status,
607 MF_TOPOSTATUS topo_status)
609 IMFMediaEvent *event;
610 PROPVARIANT param;
612 if (topo_status == MF_TOPOSTATUS_INVALID)
613 return;
615 if (list_empty(&session->topologies))
617 FIXME("Unexpectedly empty topology queue.\n");
618 return;
621 if (topo_status > session->presentation.topo_status)
623 struct queued_topology *topology = LIST_ENTRY(list_head(&session->topologies), struct queued_topology, entry);
625 param.vt = VT_UNKNOWN;
626 param.punkVal = (IUnknown *)topology->topology;
628 if (FAILED(MFCreateMediaEvent(MESessionTopologyStatus, &GUID_NULL, status, &param, &event)))
629 return;
631 session->presentation.topo_status = topo_status;
633 IMFMediaEvent_SetUINT32(event, &MF_EVENT_TOPOLOGY_STATUS, topo_status);
634 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
635 IMFMediaEvent_Release(event);
639 static HRESULT session_bind_output_nodes(IMFTopology *topology)
641 MF_TOPOLOGY_TYPE node_type;
642 IMFStreamSink *stream_sink;
643 IMFMediaSink *media_sink;
644 WORD node_count = 0, i;
645 IMFTopologyNode *node;
646 IMFActivate *activate;
647 UINT32 stream_id;
648 IUnknown *object;
649 HRESULT hr;
651 hr = IMFTopology_GetNodeCount(topology, &node_count);
653 for (i = 0; i < node_count; ++i)
655 if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
656 break;
658 if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type)) || node_type != MF_TOPOLOGY_OUTPUT_NODE)
660 IMFTopologyNode_Release(node);
661 continue;
664 if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object)))
666 stream_sink = NULL;
667 if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&stream_sink)))
669 if (SUCCEEDED(hr = IUnknown_QueryInterface(object, &IID_IMFActivate, (void **)&activate)))
671 if (SUCCEEDED(hr = IMFActivate_ActivateObject(activate, &IID_IMFMediaSink, (void **)&media_sink)))
673 if (FAILED(IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_STREAMID, &stream_id)))
674 stream_id = 0;
676 stream_sink = NULL;
677 if (FAILED(IMFMediaSink_GetStreamSinkById(media_sink, stream_id, &stream_sink)))
678 hr = IMFMediaSink_AddStreamSink(media_sink, stream_id, NULL, &stream_sink);
680 if (stream_sink)
681 hr = IMFTopologyNode_SetObject(node, (IUnknown *)stream_sink);
683 IMFMediaSink_Release(media_sink);
686 IMFActivate_Release(activate);
690 if (stream_sink)
691 IMFStreamSink_Release(stream_sink);
692 IUnknown_Release(object);
695 IMFTopologyNode_Release(node);
698 return hr;
701 static void session_set_caps(struct media_session *session, DWORD caps)
703 DWORD delta = session->caps ^ caps;
704 IMFMediaEvent *event;
706 /* Delta is documented to reflect rate value changes as well, but it's not clear what to compare
707 them to, since session always queries for current object rates. */
708 if (!delta)
709 return;
711 session->caps = caps;
713 if (FAILED(MFCreateMediaEvent(MESessionCapabilitiesChanged, &GUID_NULL, S_OK, NULL, &event)))
714 return;
716 IMFMediaEvent_SetUINT32(event, &MF_EVENT_SESSIONCAPS, caps);
717 IMFMediaEvent_SetUINT32(event, &MF_EVENT_SESSIONCAPS_DELTA, delta);
719 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
720 IMFMediaEvent_Release(event);
723 static void transform_release_sample(struct sample *sample)
725 list_remove(&sample->entry);
726 if (sample->sample)
727 IMFSample_Release(sample->sample);
728 heap_free(sample);
731 static void transform_stream_drop_samples(struct transform_stream *stream)
733 struct sample *sample, *sample2;
735 LIST_FOR_EACH_ENTRY_SAFE(sample, sample2, &stream->samples, struct sample, entry)
736 transform_release_sample(sample);
739 static void release_topo_node(struct topo_node *node)
741 unsigned int i;
743 switch (node->type)
745 case MF_TOPOLOGY_SOURCESTREAM_NODE:
746 if (node->u.source.source)
747 IMFMediaSource_Release(node->u.source.source);
748 break;
749 case MF_TOPOLOGY_TRANSFORM_NODE:
750 for (i = 0; i < node->u.transform.input_count; ++i)
751 transform_stream_drop_samples(&node->u.transform.inputs[i]);
752 for (i = 0; i < node->u.transform.output_count; ++i)
753 transform_stream_drop_samples(&node->u.transform.outputs[i]);
754 heap_free(node->u.transform.inputs);
755 heap_free(node->u.transform.outputs);
756 heap_free(node->u.transform.input_map);
757 heap_free(node->u.transform.output_map);
758 break;
759 case MF_TOPOLOGY_OUTPUT_NODE:
760 if (node->u.sink.allocator)
761 IMFVideoSampleAllocator_Release(node->u.sink.allocator);
762 if (node->u.sink.allocator_cb)
764 IMFVideoSampleAllocatorCallback_SetCallback(node->u.sink.allocator_cb, NULL);
765 IMFVideoSampleAllocatorCallback_Release(node->u.sink.allocator_cb);
767 break;
768 default:
772 if (node->object.object)
773 IUnknown_Release(node->object.object);
774 if (node->node)
775 IMFTopologyNode_Release(node->node);
776 heap_free(node);
779 static void session_clear_presentation(struct media_session *session)
781 struct media_source *source, *source2;
782 struct media_sink *sink, *sink2;
783 struct topo_node *node, *node2;
784 struct session_op *op, *op2;
786 IMFTopology_Clear(session->presentation.current_topology);
787 session->presentation.topo_status = MF_TOPOSTATUS_INVALID;
789 LIST_FOR_EACH_ENTRY_SAFE(source, source2, &session->presentation.sources, struct media_source, entry)
791 list_remove(&source->entry);
792 if (source->source)
793 IMFMediaSource_Release(source->source);
794 if (source->pd)
795 IMFPresentationDescriptor_Release(source->pd);
796 heap_free(source);
799 LIST_FOR_EACH_ENTRY_SAFE(node, node2, &session->presentation.nodes, struct topo_node, entry)
801 list_remove(&node->entry);
802 release_topo_node(node);
805 LIST_FOR_EACH_ENTRY_SAFE(sink, sink2, &session->presentation.sinks, struct media_sink, entry)
807 list_remove(&sink->entry);
809 if (sink->sink)
810 IMFMediaSink_Release(sink->sink);
811 if (sink->preroll)
812 IMFMediaSinkPreroll_Release(sink->preroll);
813 if (sink->event_generator)
814 IMFMediaEventGenerator_Release(sink->event_generator);
815 heap_free(sink);
818 LIST_FOR_EACH_ENTRY_SAFE(op, op2, &session->commands, struct session_op, entry)
820 list_remove(&op->entry);
821 IUnknown_Release(&op->IUnknown_iface);
825 static struct topo_node *session_get_node_by_id(const struct media_session *session, TOPOID id)
827 struct topo_node *node;
829 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
831 if (node->node_id == id)
832 return node;
835 return NULL;
838 static void session_start(struct media_session *session, const GUID *time_format, const PROPVARIANT *start_position)
840 struct media_source *source;
841 HRESULT hr;
843 switch (session->state)
845 case SESSION_STATE_STOPPED:
846 case SESSION_STATE_PAUSED:
848 session->presentation.time_format = *time_format;
849 session->presentation.start_position.vt = VT_EMPTY;
850 PropVariantCopy(&session->presentation.start_position, start_position);
852 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
854 if (!(session->presentation.flags & SESSION_FLAG_SOURCES_SUBSCRIBED))
856 if (FAILED(hr = IMFMediaSource_BeginGetEvent(source->source, &session->events_callback,
857 (IUnknown *)source->source)))
859 WARN("Failed to subscribe to source events, hr %#x.\n", hr);
863 if (FAILED(hr = IMFMediaSource_Start(source->source, source->pd, &GUID_NULL, start_position)))
864 WARN("Failed to start media source %p, hr %#x.\n", source->source, hr);
867 session->presentation.flags |= SESSION_FLAG_SOURCES_SUBSCRIBED;
868 session->state = SESSION_STATE_STARTING_SOURCES;
869 break;
870 case SESSION_STATE_STARTED:
871 FIXME("Seeking is not implemented.\n");
872 break;
873 case SESSION_STATE_CLOSED:
874 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStarted, &GUID_NULL,
875 MF_E_INVALIDREQUEST, NULL);
876 break;
877 default:
882 static void session_command_complete(struct media_session *session)
884 struct session_op *op;
885 struct list *e;
887 /* Pop current command, submit next. */
888 if ((e = list_head(&session->commands)))
890 op = LIST_ENTRY(e, struct session_op, entry);
891 list_remove(&op->entry);
892 IUnknown_Release(&op->IUnknown_iface);
895 if ((e = list_head(&session->commands)))
897 op = LIST_ENTRY(e, struct session_op, entry);
898 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface);
902 static void session_set_started(struct media_session *session)
904 struct media_source *source;
905 unsigned int caps, flags;
906 IMFMediaEvent *event;
908 session->state = SESSION_STATE_STARTED;
910 caps = session->caps | MFSESSIONCAP_PAUSE;
912 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
914 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source->source, &flags)))
916 if (!(flags & MFMEDIASOURCE_CAN_PAUSE))
918 caps &= ~MFSESSIONCAP_PAUSE;
919 break;
924 session_set_caps(session, caps);
926 if (SUCCEEDED(MFCreateMediaEvent(MESessionStarted, &GUID_NULL, S_OK, NULL, &event)))
928 IMFMediaEvent_SetUINT64(event, &MF_EVENT_PRESENTATION_TIME_OFFSET, 0);
929 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
930 IMFMediaEvent_Release(event);
932 session_command_complete(session);
935 static void session_set_paused(struct media_session *session, HRESULT status)
937 session->state = SESSION_STATE_PAUSED;
938 if (SUCCEEDED(status))
939 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
940 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionPaused, &GUID_NULL, status, NULL);
941 session_command_complete(session);
944 static void session_set_closed(struct media_session *session, HRESULT status)
946 session->state = SESSION_STATE_CLOSED;
947 if (SUCCEEDED(status))
948 session_set_caps(session, session->caps & ~(MFSESSIONCAP_START | MFSESSIONCAP_SEEK));
949 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionClosed, &GUID_NULL, status, NULL);
950 session_command_complete(session);
953 static void session_pause(struct media_session *session)
955 HRESULT hr;
957 switch (session->state)
959 case SESSION_STATE_STARTED:
961 /* Transition in two steps - pause clock, wait for sinks and pause sources. */
962 if (SUCCEEDED(hr = IMFPresentationClock_Pause(session->clock)))
963 session->state = SESSION_STATE_PAUSING_SINKS;
965 break;
966 default:
967 hr = MF_E_INVALIDREQUEST;
970 if (FAILED(hr))
971 session_set_paused(session, hr);
974 static void session_set_stopped(struct media_session *session, HRESULT status)
976 MediaEventType event_type;
977 IMFMediaEvent *event;
979 session->state = SESSION_STATE_STOPPED;
980 event_type = session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION ? MESessionEnded : MESessionStopped;
982 if (SUCCEEDED(MFCreateMediaEvent(event_type, &GUID_NULL, status, NULL, &event)))
984 IMFMediaEvent_SetUINT64(event, &MF_SESSION_APPROX_EVENT_OCCURRENCE_TIME, session->presentation.clock_stop_time);
985 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
986 IMFMediaEvent_Release(event);
988 session_command_complete(session);
991 static void session_stop(struct media_session *session)
993 HRESULT hr = MF_E_INVALIDREQUEST;
995 switch (session->state)
997 case SESSION_STATE_STARTED:
998 case SESSION_STATE_PAUSED:
1000 /* Transition in two steps - pause clock, wait for sinks and pause sources. */
1001 IMFPresentationClock_GetTime(session->clock, &session->presentation.clock_stop_time);
1002 if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock)))
1003 session->state = SESSION_STATE_STOPPING_SINKS;
1004 else
1005 session_set_stopped(session, hr);
1007 break;
1008 case SESSION_STATE_STOPPED:
1009 hr = S_OK;
1010 /* fallthrough */
1011 default:
1012 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStopped, &GUID_NULL, hr, NULL);
1013 session_command_complete(session);
1014 break;
1018 static HRESULT session_finalize_sinks(struct media_session *session)
1020 IMFFinalizableMediaSink *fin_sink;
1021 BOOL sinks_finalized = TRUE;
1022 struct media_sink *sink;
1023 HRESULT hr = S_OK;
1025 session->presentation.flags &= ~SESSION_FLAG_FINALIZE_SINKS;
1026 session->state = SESSION_STATE_FINALIZING_SINKS;
1028 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
1030 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink->sink, &IID_IMFFinalizableMediaSink, (void **)&fin_sink)))
1032 hr = IMFFinalizableMediaSink_BeginFinalize(fin_sink, &session->sink_finalizer_callback,
1033 (IUnknown *)fin_sink);
1034 IMFFinalizableMediaSink_Release(fin_sink);
1035 if (FAILED(hr))
1036 break;
1037 sinks_finalized = FALSE;
1039 else
1040 sink->finalized = TRUE;
1043 if (sinks_finalized)
1044 session_set_closed(session, hr);
1046 return hr;
1049 static void session_close(struct media_session *session)
1051 HRESULT hr = S_OK;
1053 switch (session->state)
1055 case SESSION_STATE_STOPPED:
1056 hr = session_finalize_sinks(session);
1057 break;
1058 case SESSION_STATE_STARTED:
1059 case SESSION_STATE_PAUSED:
1060 session->presentation.flags |= SESSION_FLAG_FINALIZE_SINKS;
1061 if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock)))
1062 session->state = SESSION_STATE_STOPPING_SINKS;
1063 break;
1064 default:
1065 hr = MF_E_INVALIDREQUEST;
1066 break;
1069 if (FAILED(hr))
1070 session_set_closed(session, hr);
1073 static struct media_source *session_get_media_source(struct media_session *session, IMFMediaSource *source)
1075 struct media_source *cur;
1077 LIST_FOR_EACH_ENTRY(cur, &session->presentation.sources, struct media_source, entry)
1079 if (source == cur->source)
1080 return cur;
1083 return NULL;
1086 static void session_release_media_source(struct media_source *source)
1088 IMFMediaSource_Release(source->source);
1089 if (source->pd)
1090 IMFPresentationDescriptor_Release(source->pd);
1091 heap_free(source);
1094 static HRESULT session_add_media_source(struct media_session *session, IMFTopologyNode *node, IMFMediaSource *source)
1096 struct media_source *media_source;
1097 HRESULT hr;
1099 if (session_get_media_source(session, source))
1100 return S_FALSE;
1102 if (!(media_source = heap_alloc_zero(sizeof(*media_source))))
1103 return E_OUTOFMEMORY;
1105 media_source->source = source;
1106 IMFMediaSource_AddRef(media_source->source);
1108 hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, &IID_IMFPresentationDescriptor,
1109 (void **)&media_source->pd);
1111 if (SUCCEEDED(hr))
1112 list_add_tail(&session->presentation.sources, &media_source->entry);
1113 else
1114 session_release_media_source(media_source);
1116 return hr;
1119 static void session_raise_topology_set(struct media_session *session, IMFTopology *topology, HRESULT status)
1121 PROPVARIANT param;
1123 param.vt = topology ? VT_UNKNOWN : VT_EMPTY;
1124 param.punkVal = (IUnknown *)topology;
1126 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologySet, &GUID_NULL, status, &param);
1129 static DWORD session_get_object_rate_caps(IUnknown *object)
1131 IMFRateSupport *rate_support;
1132 DWORD caps = 0;
1133 float rate;
1135 if (SUCCEEDED(MFGetService(object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support)))
1137 rate = 0.0f;
1138 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support, MFRATE_FORWARD, TRUE, &rate)) && rate != 0.0f)
1139 caps |= MFSESSIONCAP_RATE_FORWARD;
1141 rate = 0.0f;
1142 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support, MFRATE_REVERSE, TRUE, &rate)) && rate != 0.0f)
1143 caps |= MFSESSIONCAP_RATE_REVERSE;
1145 IMFRateSupport_Release(rate_support);
1148 return caps;
1151 static HRESULT session_add_media_sink(struct media_session *session, IMFTopologyNode *node, IMFMediaSink *sink)
1153 struct media_sink *media_sink;
1154 DWORD flags;
1156 LIST_FOR_EACH_ENTRY(media_sink, &session->presentation.sinks, struct media_sink, entry)
1158 if (sink == media_sink->sink)
1159 return S_FALSE;
1162 if (!(media_sink = heap_alloc_zero(sizeof(*media_sink))))
1163 return E_OUTOFMEMORY;
1165 media_sink->sink = sink;
1166 IMFMediaSink_AddRef(media_sink->sink);
1168 IMFMediaSink_QueryInterface(media_sink->sink, &IID_IMFMediaEventGenerator, (void **)&media_sink->event_generator);
1170 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink, &flags)) && flags & MEDIASINK_CAN_PREROLL)
1172 if (SUCCEEDED(IMFMediaSink_QueryInterface(media_sink->sink, &IID_IMFMediaSinkPreroll, (void **)&media_sink->preroll)))
1173 session->presentation.flags |= SESSION_FLAG_NEEDS_PREROLL;
1176 list_add_tail(&session->presentation.sinks, &media_sink->entry);
1178 return S_OK;
1181 static HRESULT session_set_transform_stream_info(struct topo_node *node)
1183 unsigned int *input_map = NULL, *output_map = NULL;
1184 unsigned int i, input_count, output_count;
1185 struct transform_stream *streams;
1186 HRESULT hr;
1188 hr = IMFTransform_GetStreamCount(node->object.transform, &input_count, &output_count);
1189 if (SUCCEEDED(hr) && (input_count > 1 || output_count > 1))
1191 input_map = heap_calloc(input_count, sizeof(*input_map));
1192 output_map = heap_calloc(output_count, sizeof(*output_map));
1193 if (FAILED(IMFTransform_GetStreamIDs(node->object.transform, input_count, input_map,
1194 output_count, output_map)))
1196 /* Assume sequential identifiers. */
1197 heap_free(input_map);
1198 heap_free(output_map);
1199 input_map = output_map = NULL;
1203 if (SUCCEEDED(hr))
1205 streams = heap_calloc(input_count, sizeof(*streams));
1206 for (i = 0; i < input_count; ++i)
1207 list_init(&streams[i].samples);
1208 node->u.transform.inputs = streams;
1210 streams = heap_calloc(output_count, sizeof(*streams));
1211 for (i = 0; i < output_count; ++i)
1212 list_init(&streams[i].samples);
1213 node->u.transform.outputs = streams;
1215 node->u.transform.input_count = input_count;
1216 node->u.transform.output_count = output_count;
1217 node->u.transform.input_map = input_map;
1218 node->u.transform.output_map = output_map;
1221 return hr;
1224 static HRESULT session_get_stream_sink_type(IMFStreamSink *sink, IMFMediaType **media_type)
1226 IMFMediaTypeHandler *handler;
1227 HRESULT hr;
1229 if (SUCCEEDED(hr = IMFStreamSink_GetMediaTypeHandler(sink, &handler)))
1231 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, media_type);
1232 IMFMediaTypeHandler_Release(handler);
1235 return hr;
1238 static HRESULT WINAPI node_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify *iface,
1239 REFIID riid, void **obj)
1241 if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorNotify) ||
1242 IsEqualIID(riid, &IID_IUnknown))
1244 *obj = iface;
1245 IMFVideoSampleAllocatorNotify_AddRef(iface);
1246 return S_OK;
1249 *obj = NULL;
1250 return E_NOINTERFACE;
1253 static ULONG WINAPI node_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify *iface)
1255 return 2;
1258 static ULONG WINAPI node_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify *iface)
1260 return 1;
1263 static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output);
1265 static HRESULT WINAPI node_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify *iface)
1267 struct topo_node *topo_node = impl_node_from_IMFVideoSampleAllocatorNotify(iface);
1268 struct session_op *op;
1270 if (SUCCEEDED(create_session_op(SESSION_CMD_SA_READY, &op)))
1272 op->u.sa_ready.node_id = topo_node->node_id;
1273 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &topo_node->session->commands_callback, &op->IUnknown_iface);
1274 IUnknown_Release(&op->IUnknown_iface);
1277 return S_OK;
1280 static const IMFVideoSampleAllocatorNotifyVtbl node_sample_allocator_cb_vtbl =
1282 node_sample_allocator_cb_QueryInterface,
1283 node_sample_allocator_cb_AddRef,
1284 node_sample_allocator_cb_Release,
1285 node_sample_allocator_cb_NotifyRelease,
1288 static HRESULT session_append_node(struct media_session *session, IMFTopologyNode *node)
1290 struct topo_node *topo_node;
1291 IMFMediaSink *media_sink;
1292 IMFMediaType *media_type;
1293 IMFStreamDescriptor *sd;
1294 HRESULT hr = S_OK;
1295 IUnknown *object;
1297 if (!(topo_node = heap_alloc_zero(sizeof(*topo_node))))
1298 return E_OUTOFMEMORY;
1300 IMFTopologyNode_GetNodeType(node, &topo_node->type);
1301 IMFTopologyNode_GetTopoNodeID(node, &topo_node->node_id);
1302 topo_node->node = node;
1303 IMFTopologyNode_AddRef(topo_node->node);
1304 topo_node->session = session;
1306 switch (topo_node->type)
1308 case MF_TOPOLOGY_OUTPUT_NODE:
1309 topo_node->u.sink.notify_cb.lpVtbl = &node_sample_allocator_cb_vtbl;
1311 if (FAILED(hr = IMFTopologyNode_GetObject(node, &object)))
1313 WARN("Node %s does not have associated object.\n", wine_dbgstr_longlong(topo_node->node_id));
1314 break;
1316 hr = IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&topo_node->object.object);
1317 IUnknown_Release(object);
1318 if (FAILED(hr))
1319 break;
1321 if (FAILED(hr = IMFStreamSink_GetMediaSink(topo_node->object.sink_stream, &media_sink)))
1322 break;
1324 if (SUCCEEDED(hr = session_add_media_sink(session, node, media_sink)))
1326 if (SUCCEEDED(session_get_stream_sink_type(topo_node->object.sink_stream, &media_type)))
1328 if (SUCCEEDED(MFGetService(topo_node->object.object, &MR_VIDEO_ACCELERATION_SERVICE,
1329 &IID_IMFVideoSampleAllocator, (void **)&topo_node->u.sink.allocator)))
1331 IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node->u.sink.allocator, 2, media_type);
1332 IMFVideoSampleAllocator_QueryInterface(topo_node->u.sink.allocator,
1333 &IID_IMFVideoSampleAllocatorCallback, (void **)&topo_node->u.sink.allocator_cb);
1334 IMFVideoSampleAllocatorCallback_SetCallback(topo_node->u.sink.allocator_cb,
1335 &topo_node->u.sink.notify_cb);
1337 IMFMediaType_Release(media_type);
1340 IMFMediaSink_Release(media_sink);
1342 break;
1343 case MF_TOPOLOGY_SOURCESTREAM_NODE:
1344 if (FAILED(IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_SOURCE, &IID_IMFMediaSource,
1345 (void **)&topo_node->u.source.source)))
1347 WARN("Missing MF_TOPONODE_SOURCE, hr %#x.\n", hr);
1348 break;
1351 if (FAILED(hr = session_add_media_source(session, node, topo_node->u.source.source)))
1352 break;
1354 if (FAILED(hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR,
1355 &IID_IMFStreamDescriptor, (void **)&sd)))
1357 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#x.\n", hr);
1358 break;
1361 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &topo_node->u.source.stream_id);
1362 IMFStreamDescriptor_Release(sd);
1364 break;
1365 case MF_TOPOLOGY_TRANSFORM_NODE:
1366 if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object)))
1368 hr = IUnknown_QueryInterface(object, &IID_IMFTransform, (void **)&topo_node->object.transform);
1369 IUnknown_Release(object);
1372 if (SUCCEEDED(hr))
1373 hr = session_set_transform_stream_info(topo_node);
1374 else
1375 WARN("Failed to get IMFTransform for MFT node, hr %#x.\n", hr);
1377 break;
1378 case MF_TOPOLOGY_TEE_NODE:
1379 FIXME("Unsupported node type %d.\n", topo_node->type);
1381 break;
1382 default:
1386 if (SUCCEEDED(hr))
1387 list_add_tail(&session->presentation.nodes, &topo_node->entry);
1388 else
1389 release_topo_node(topo_node);
1391 return hr;
1394 static HRESULT session_collect_nodes(struct media_session *session)
1396 IMFTopology *topology = session->presentation.current_topology;
1397 IMFTopologyNode *node;
1398 WORD i, count = 0;
1399 HRESULT hr;
1401 if (!list_empty(&session->presentation.nodes))
1402 return S_OK;
1404 if (FAILED(hr = IMFTopology_GetNodeCount(topology, &count)))
1405 return hr;
1407 for (i = 0; i < count; ++i)
1409 if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
1411 WARN("Failed to get node %u.\n", i);
1412 break;
1415 hr = session_append_node(session, node);
1416 IMFTopologyNode_Release(node);
1417 if (FAILED(hr))
1419 WARN("Failed to add node %u.\n", i);
1420 break;
1424 return hr;
1427 static HRESULT session_set_current_topology(struct media_session *session, IMFTopology *topology)
1429 struct media_source *source;
1430 DWORD caps, object_flags;
1431 struct media_sink *sink;
1432 struct topo_node *node;
1433 struct session_op *op;
1434 IMFMediaEvent *event;
1435 HRESULT hr;
1437 if (session->quality_manager)
1439 if (SUCCEEDED(create_session_op(SESSION_CMD_QM_NOTIFY_TOPOLOGY, &op)))
1441 op->u.notify_topology.topology = topology;
1442 IMFTopology_AddRef(op->u.notify_topology.topology);
1443 session_submit_command(session, op);
1444 IUnknown_Release(&op->IUnknown_iface);
1448 if (FAILED(hr = IMFTopology_CloneFrom(session->presentation.current_topology, topology)))
1450 WARN("Failed to clone topology, hr %#x.\n", hr);
1451 return hr;
1454 session_collect_nodes(session);
1456 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
1458 if (node->type == MF_TOPOLOGY_TRANSFORM_NODE)
1460 if (FAILED(hr = IMFTransform_ProcessMessage(node->object.transform,
1461 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0)))
1462 return hr;
1466 /* FIXME: attributes are all zero for now */
1467 if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime, &GUID_NULL, S_OK, NULL, &event)))
1469 IMFMediaEvent_SetUINT64(event, &MF_EVENT_START_PRESENTATION_TIME, 0);
1470 IMFMediaEvent_SetUINT64(event, &MF_EVENT_PRESENTATION_TIME_OFFSET, 0);
1471 IMFMediaEvent_SetUINT64(event, &MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT, 0);
1473 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
1474 IMFMediaEvent_Release(event);
1477 /* Update session caps. */
1478 caps = MFSESSIONCAP_START | MFSESSIONCAP_SEEK | MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE |
1479 MFSESSIONCAP_DOES_NOT_USE_NETWORK;
1481 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
1483 if (!caps)
1484 break;
1486 object_flags = 0;
1487 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source->source, &object_flags)))
1489 if (!(object_flags & MFMEDIASOURCE_DOES_NOT_USE_NETWORK))
1490 caps &= ~MFSESSIONCAP_DOES_NOT_USE_NETWORK;
1491 if (!(object_flags & MFMEDIASOURCE_CAN_SEEK))
1492 caps &= ~MFSESSIONCAP_SEEK;
1495 /* Mask unsupported rate caps. */
1497 caps &= session_get_object_rate_caps((IUnknown *)source->source)
1498 | ~(MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE);
1501 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
1503 if (!caps)
1504 break;
1506 object_flags = 0;
1507 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink->sink, &object_flags)))
1509 if (!(object_flags & MEDIASINK_RATELESS))
1510 caps &= session_get_object_rate_caps((IUnknown *)sink->sink)
1511 | ~(MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE);
1515 session_set_caps(session, caps);
1517 return S_OK;
1520 static void session_set_topology(struct media_session *session, DWORD flags, IMFTopology *topology)
1522 IMFTopology *resolved_topology = NULL;
1523 HRESULT hr = S_OK;
1525 /* Resolve unless claimed to be full. */
1526 if (!(flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT) && topology)
1528 if (!(flags & MFSESSION_SETTOPOLOGY_NORESOLUTION))
1530 hr = session_bind_output_nodes(topology);
1532 if (SUCCEEDED(hr))
1533 hr = IMFTopoLoader_Load(session->topo_loader, topology, &resolved_topology, NULL /* FIXME? */);
1535 if (SUCCEEDED(hr))
1537 topology = resolved_topology;
1542 if (flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT)
1544 if ((topology && topology == session->presentation.current_topology) || !topology)
1546 /* FIXME: stop current topology, queue next one. */
1547 session_clear_presentation(session);
1549 else
1550 hr = S_FALSE;
1552 topology = NULL;
1554 else if (topology && flags & MFSESSION_SETTOPOLOGY_IMMEDIATE)
1556 session_clear_topologies(session);
1557 session_clear_presentation(session);
1560 session_raise_topology_set(session, topology, hr);
1562 /* With no current topology set it right away, otherwise queue. */
1563 if (topology)
1565 struct queued_topology *queued_topology;
1567 if ((queued_topology = heap_alloc_zero(sizeof(*queued_topology))))
1569 queued_topology->topology = topology;
1570 IMFTopology_AddRef(queued_topology->topology);
1572 list_add_tail(&session->topologies, &queued_topology->entry);
1575 if (session->presentation.topo_status == MF_TOPOSTATUS_INVALID)
1577 hr = session_set_current_topology(session, topology);
1578 session_set_topo_status(session, hr, MF_TOPOSTATUS_READY);
1582 if (resolved_topology)
1583 IMFTopology_Release(resolved_topology);
1586 static HRESULT WINAPI mfsession_QueryInterface(IMFMediaSession *iface, REFIID riid, void **out)
1588 struct media_session *session = impl_from_IMFMediaSession(iface);
1590 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1592 if (IsEqualIID(riid, &IID_IMFMediaSession) ||
1593 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
1594 IsEqualIID(riid, &IID_IUnknown))
1596 *out = &session->IMFMediaSession_iface;
1597 IMFMediaSession_AddRef(iface);
1598 return S_OK;
1600 else if (IsEqualIID(riid, &IID_IMFGetService))
1602 *out = &session->IMFGetService_iface;
1603 IMFMediaSession_AddRef(iface);
1604 return S_OK;
1607 WARN("Unsupported %s.\n", debugstr_guid(riid));
1608 *out = NULL;
1609 return E_NOINTERFACE;
1612 static ULONG WINAPI mfsession_AddRef(IMFMediaSession *iface)
1614 struct media_session *session = impl_from_IMFMediaSession(iface);
1615 ULONG refcount = InterlockedIncrement(&session->refcount);
1617 TRACE("%p, refcount %u.\n", iface, refcount);
1619 return refcount;
1622 static ULONG WINAPI mfsession_Release(IMFMediaSession *iface)
1624 struct media_session *session = impl_from_IMFMediaSession(iface);
1625 ULONG refcount = InterlockedDecrement(&session->refcount);
1627 TRACE("%p, refcount %u.\n", iface, refcount);
1629 if (!refcount)
1631 session_clear_topologies(session);
1632 session_clear_presentation(session);
1633 if (session->presentation.current_topology)
1634 IMFTopology_Release(session->presentation.current_topology);
1635 if (session->event_queue)
1636 IMFMediaEventQueue_Release(session->event_queue);
1637 if (session->clock)
1638 IMFPresentationClock_Release(session->clock);
1639 if (session->system_time_source)
1640 IMFPresentationTimeSource_Release(session->system_time_source);
1641 if (session->clock_rate_control)
1642 IMFRateControl_Release(session->clock_rate_control);
1643 if (session->topo_loader)
1644 IMFTopoLoader_Release(session->topo_loader);
1645 if (session->quality_manager)
1646 IMFQualityManager_Release(session->quality_manager);
1647 DeleteCriticalSection(&session->cs);
1648 heap_free(session);
1651 return refcount;
1654 static HRESULT WINAPI mfsession_GetEvent(IMFMediaSession *iface, DWORD flags, IMFMediaEvent **event)
1656 struct media_session *session = impl_from_IMFMediaSession(iface);
1658 TRACE("%p, %#x, %p.\n", iface, flags, event);
1660 return IMFMediaEventQueue_GetEvent(session->event_queue, flags, event);
1663 static HRESULT WINAPI mfsession_BeginGetEvent(IMFMediaSession *iface, IMFAsyncCallback *callback, IUnknown *state)
1665 struct media_session *session = impl_from_IMFMediaSession(iface);
1667 TRACE("%p, %p, %p.\n", iface, callback, state);
1669 return IMFMediaEventQueue_BeginGetEvent(session->event_queue, callback, state);
1672 static HRESULT WINAPI mfsession_EndGetEvent(IMFMediaSession *iface, IMFAsyncResult *result, IMFMediaEvent **event)
1674 struct media_session *session = impl_from_IMFMediaSession(iface);
1676 TRACE("%p, %p, %p.\n", iface, result, event);
1678 return IMFMediaEventQueue_EndGetEvent(session->event_queue, result, event);
1681 static HRESULT WINAPI mfsession_QueueEvent(IMFMediaSession *iface, MediaEventType event_type, REFGUID ext_type,
1682 HRESULT hr, const PROPVARIANT *value)
1684 struct media_session *session = impl_from_IMFMediaSession(iface);
1686 TRACE("%p, %d, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
1688 return IMFMediaEventQueue_QueueEventParamVar(session->event_queue, event_type, ext_type, hr, value);
1691 static HRESULT WINAPI mfsession_SetTopology(IMFMediaSession *iface, DWORD flags, IMFTopology *topology)
1693 struct media_session *session = impl_from_IMFMediaSession(iface);
1694 struct session_op *op;
1695 WORD node_count = 0;
1696 HRESULT hr;
1698 TRACE("%p, %#x, %p.\n", iface, flags, topology);
1700 if (topology)
1702 if (FAILED(IMFTopology_GetNodeCount(topology, &node_count)) || node_count == 0)
1703 return E_INVALIDARG;
1706 if (FAILED(hr = create_session_op(SESSION_CMD_SET_TOPOLOGY, &op)))
1707 return hr;
1709 op->u.set_topology.flags = flags;
1710 op->u.set_topology.topology = topology;
1711 if (op->u.set_topology.topology)
1712 IMFTopology_AddRef(op->u.set_topology.topology);
1714 hr = session_submit_command(session, op);
1715 IUnknown_Release(&op->IUnknown_iface);
1717 return hr;
1720 static HRESULT WINAPI mfsession_ClearTopologies(IMFMediaSession *iface)
1722 struct media_session *session = impl_from_IMFMediaSession(iface);
1724 TRACE("%p.\n", iface);
1726 return session_submit_simple_command(session, SESSION_CMD_CLEAR_TOPOLOGIES);
1729 static HRESULT WINAPI mfsession_Start(IMFMediaSession *iface, const GUID *format, const PROPVARIANT *start_position)
1731 struct media_session *session = impl_from_IMFMediaSession(iface);
1732 struct session_op *op;
1733 HRESULT hr;
1735 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), start_position);
1737 if (!start_position)
1738 return E_POINTER;
1740 if (FAILED(hr = create_session_op(SESSION_CMD_START, &op)))
1741 return hr;
1743 op->u.start.time_format = format ? *format : GUID_NULL;
1744 hr = PropVariantCopy(&op->u.start.start_position, start_position);
1746 if (SUCCEEDED(hr))
1747 hr = session_submit_command(session, op);
1749 IUnknown_Release(&op->IUnknown_iface);
1751 return hr;
1754 static HRESULT WINAPI mfsession_Pause(IMFMediaSession *iface)
1756 struct media_session *session = impl_from_IMFMediaSession(iface);
1758 TRACE("%p.\n", iface);
1760 return session_submit_simple_command(session, SESSION_CMD_PAUSE);
1763 static HRESULT WINAPI mfsession_Stop(IMFMediaSession *iface)
1765 struct media_session *session = impl_from_IMFMediaSession(iface);
1767 TRACE("%p.\n", iface);
1769 return session_submit_simple_command(session, SESSION_CMD_STOP);
1772 static HRESULT WINAPI mfsession_Close(IMFMediaSession *iface)
1774 struct media_session *session = impl_from_IMFMediaSession(iface);
1776 TRACE("%p.\n", iface);
1778 return session_submit_simple_command(session, SESSION_CMD_CLOSE);
1781 static HRESULT WINAPI mfsession_Shutdown(IMFMediaSession *iface)
1783 struct media_session *session = impl_from_IMFMediaSession(iface);
1784 HRESULT hr = S_OK;
1786 FIXME("%p.\n", iface);
1788 EnterCriticalSection(&session->cs);
1789 if (SUCCEEDED(hr = session_is_shut_down(session)))
1791 session->state = SESSION_STATE_SHUT_DOWN;
1792 IMFMediaEventQueue_Shutdown(session->event_queue);
1793 if (session->quality_manager)
1794 IMFQualityManager_Shutdown(session->quality_manager);
1795 MFShutdownObject((IUnknown *)session->clock);
1796 IMFPresentationClock_Release(session->clock);
1797 session->clock = NULL;
1799 LeaveCriticalSection(&session->cs);
1801 return hr;
1804 static HRESULT WINAPI mfsession_GetClock(IMFMediaSession *iface, IMFClock **clock)
1806 struct media_session *session = impl_from_IMFMediaSession(iface);
1807 HRESULT hr;
1809 TRACE("%p, %p.\n", iface, clock);
1811 EnterCriticalSection(&session->cs);
1812 if (SUCCEEDED(hr = session_is_shut_down(session)))
1814 *clock = (IMFClock *)session->clock;
1815 IMFClock_AddRef(*clock);
1817 LeaveCriticalSection(&session->cs);
1819 return hr;
1822 static HRESULT WINAPI mfsession_GetSessionCapabilities(IMFMediaSession *iface, DWORD *caps)
1824 struct media_session *session = impl_from_IMFMediaSession(iface);
1825 HRESULT hr = S_OK;
1827 TRACE("%p, %p.\n", iface, caps);
1829 if (!caps)
1830 return E_POINTER;
1832 EnterCriticalSection(&session->cs);
1833 if (SUCCEEDED(hr = session_is_shut_down(session)))
1834 *caps = session->caps;
1835 LeaveCriticalSection(&session->cs);
1837 return hr;
1840 static HRESULT WINAPI mfsession_GetFullTopology(IMFMediaSession *iface, DWORD flags, TOPOID id, IMFTopology **topology)
1842 struct media_session *session = impl_from_IMFMediaSession(iface);
1843 struct queued_topology *queued;
1844 TOPOID topo_id;
1845 HRESULT hr;
1847 TRACE("%p, %#x, %s, %p.\n", iface, flags, wine_dbgstr_longlong(id), topology);
1849 *topology = NULL;
1851 EnterCriticalSection(&session->cs);
1853 if (SUCCEEDED(hr = session_is_shut_down(session)))
1855 if (flags & MFSESSION_GETFULLTOPOLOGY_CURRENT)
1857 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
1858 *topology = session->presentation.current_topology;
1859 else
1860 hr = MF_E_INVALIDREQUEST;
1862 else
1864 LIST_FOR_EACH_ENTRY(queued, &session->topologies, struct queued_topology, entry)
1866 if (SUCCEEDED(IMFTopology_GetTopologyID(queued->topology, &topo_id)) && topo_id == id)
1868 *topology = queued->topology;
1869 break;
1874 if (*topology)
1875 IMFTopology_AddRef(*topology);
1878 LeaveCriticalSection(&session->cs);
1880 return hr;
1883 static const IMFMediaSessionVtbl mfmediasessionvtbl =
1885 mfsession_QueryInterface,
1886 mfsession_AddRef,
1887 mfsession_Release,
1888 mfsession_GetEvent,
1889 mfsession_BeginGetEvent,
1890 mfsession_EndGetEvent,
1891 mfsession_QueueEvent,
1892 mfsession_SetTopology,
1893 mfsession_ClearTopologies,
1894 mfsession_Start,
1895 mfsession_Pause,
1896 mfsession_Stop,
1897 mfsession_Close,
1898 mfsession_Shutdown,
1899 mfsession_GetClock,
1900 mfsession_GetSessionCapabilities,
1901 mfsession_GetFullTopology,
1904 static HRESULT WINAPI session_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1906 struct media_session *session = impl_from_IMFGetService(iface);
1907 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
1910 static ULONG WINAPI session_get_service_AddRef(IMFGetService *iface)
1912 struct media_session *session = impl_from_IMFGetService(iface);
1913 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
1916 static ULONG WINAPI session_get_service_Release(IMFGetService *iface)
1918 struct media_session *session = impl_from_IMFGetService(iface);
1919 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
1922 static HRESULT WINAPI session_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
1924 struct media_session *session = impl_from_IMFGetService(iface);
1926 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1928 *obj = NULL;
1930 if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE))
1932 if (IsEqualIID(riid, &IID_IMFRateSupport))
1934 *obj = &session->IMFRateSupport_iface;
1936 else if (IsEqualIID(riid, &IID_IMFRateControl))
1938 *obj = &session->IMFRateControl_iface;
1941 else if (IsEqualGUID(service, &MF_LOCAL_MFT_REGISTRATION_SERVICE))
1943 return IMFLocalMFTRegistration_QueryInterface(&local_mft_registration, riid, obj);
1945 else if (IsEqualGUID(service, &MR_VIDEO_RENDER_SERVICE))
1947 IMFStreamSink *stream_sink;
1948 IMFTopologyNode *node;
1949 IUnknown *vr, *object;
1950 IMFCollection *nodes;
1951 IMFMediaSink *sink;
1952 unsigned int i = 0;
1953 HRESULT hr;
1955 EnterCriticalSection(&session->cs);
1957 /* Use first sink to support IMFVideoRenderer. */
1958 if (session->presentation.current_topology)
1960 if (SUCCEEDED(IMFTopology_GetOutputNodeCollection(session->presentation.current_topology,
1961 &nodes)))
1963 while (IMFCollection_GetElement(nodes, i++, (IUnknown **)&node) == S_OK)
1965 if (SUCCEEDED(IMFTopologyNode_GetObject(node, &object)))
1967 if (SUCCEEDED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&stream_sink)))
1969 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink)))
1971 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink, &IID_IMFVideoRenderer, (void **)&vr)))
1973 if (FAILED(hr = MFGetService(vr, service, riid, obj)))
1974 WARN("Failed to get service from video renderer %#x.\n", hr);
1975 IUnknown_Release(vr);
1978 IMFStreamSink_Release(stream_sink);
1981 IUnknown_Release(object);
1984 IMFTopologyNode_Release(node);
1986 if (*obj)
1987 break;
1990 IMFCollection_Release(nodes);
1994 LeaveCriticalSection(&session->cs);
1996 else
1997 FIXME("Unsupported service %s.\n", debugstr_guid(service));
1999 if (*obj)
2000 IUnknown_AddRef((IUnknown *)*obj);
2002 return *obj ? S_OK : E_NOINTERFACE;
2005 static const IMFGetServiceVtbl session_get_service_vtbl =
2007 session_get_service_QueryInterface,
2008 session_get_service_AddRef,
2009 session_get_service_Release,
2010 session_get_service_GetService,
2013 static HRESULT WINAPI session_commands_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
2015 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
2016 IsEqualIID(riid, &IID_IUnknown))
2018 *obj = iface;
2019 IMFAsyncCallback_AddRef(iface);
2020 return S_OK;
2023 WARN("Unsupported %s.\n", debugstr_guid(riid));
2024 *obj = NULL;
2025 return E_NOINTERFACE;
2028 static ULONG WINAPI session_commands_callback_AddRef(IMFAsyncCallback *iface)
2030 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2031 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2034 static ULONG WINAPI session_commands_callback_Release(IMFAsyncCallback *iface)
2036 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2037 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2040 static HRESULT WINAPI session_commands_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
2042 return E_NOTIMPL;
2045 static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
2047 struct session_op *op = impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result));
2048 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2049 struct topo_node *topo_node;
2050 IMFTopologyNode *upstream_node;
2051 unsigned int upstream_output;
2053 EnterCriticalSection(&session->cs);
2055 switch (op->command)
2057 case SESSION_CMD_CLEAR_TOPOLOGIES:
2058 session_clear_topologies(session);
2059 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologiesCleared, &GUID_NULL,
2060 S_OK, NULL);
2061 session_command_complete(session);
2062 break;
2063 case SESSION_CMD_SET_TOPOLOGY:
2064 session_set_topology(session, op->u.set_topology.flags, op->u.set_topology.topology);
2065 session_command_complete(session);
2066 break;
2067 case SESSION_CMD_START:
2068 session_start(session, &op->u.start.time_format, &op->u.start.start_position);
2069 break;
2070 case SESSION_CMD_PAUSE:
2071 session_pause(session);
2072 break;
2073 case SESSION_CMD_STOP:
2074 session_stop(session);
2075 break;
2076 case SESSION_CMD_CLOSE:
2077 session_close(session);
2078 break;
2079 case SESSION_CMD_QM_NOTIFY_TOPOLOGY:
2080 IMFQualityManager_NotifyTopology(session->quality_manager, op->u.notify_topology.topology);
2081 session_command_complete(session);
2082 break;
2083 case SESSION_CMD_SA_READY:
2084 topo_node = session_get_node_by_id(session, op->u.sa_ready.node_id);
2086 if (topo_node->u.sink.requests)
2088 if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node->node, 0, &upstream_node, &upstream_output)))
2090 session_request_sample_from_node(session, upstream_node, upstream_output);
2091 IMFTopologyNode_Release(upstream_node);
2094 break;
2095 default:
2099 LeaveCriticalSection(&session->cs);
2101 return S_OK;
2104 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl =
2106 session_commands_callback_QueryInterface,
2107 session_commands_callback_AddRef,
2108 session_commands_callback_Release,
2109 session_commands_callback_GetParameters,
2110 session_commands_callback_Invoke,
2113 static HRESULT WINAPI session_events_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
2115 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
2116 IsEqualIID(riid, &IID_IUnknown))
2118 *obj = iface;
2119 IMFAsyncCallback_AddRef(iface);
2120 return S_OK;
2123 WARN("Unsupported %s.\n", debugstr_guid(riid));
2124 *obj = NULL;
2125 return E_NOINTERFACE;
2128 static ULONG WINAPI session_events_callback_AddRef(IMFAsyncCallback *iface)
2130 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
2131 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2134 static ULONG WINAPI session_events_callback_Release(IMFAsyncCallback *iface)
2136 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
2137 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2140 static HRESULT WINAPI session_events_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
2142 return E_NOTIMPL;
2145 static HRESULT session_add_media_stream(struct media_session *session, IMFMediaSource *source, IMFMediaStream *stream)
2147 struct topo_node *node;
2148 IMFStreamDescriptor *sd;
2149 DWORD stream_id = 0;
2150 HRESULT hr;
2152 if (FAILED(hr = IMFMediaStream_GetStreamDescriptor(stream, &sd)))
2153 return hr;
2155 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &stream_id);
2156 IMFStreamDescriptor_Release(sd);
2157 if (FAILED(hr))
2158 return hr;
2160 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2162 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->u.source.source == source
2163 && node->u.source.stream_id == stream_id)
2165 if (node->object.source_stream)
2167 WARN("Node already has stream set.\n");
2168 return S_FALSE;
2171 node->object.source_stream = stream;
2172 IMFMediaStream_AddRef(node->object.source_stream);
2173 break;
2177 return S_OK;
2180 static BOOL session_is_source_nodes_state(struct media_session *session, enum object_state state)
2182 struct media_source *source;
2183 struct topo_node *node;
2185 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2187 if (source->state != state)
2188 return FALSE;
2191 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2193 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->state != state)
2194 return FALSE;
2197 return TRUE;
2200 static BOOL session_is_output_nodes_state(struct media_session *session, enum object_state state)
2202 struct topo_node *node;
2204 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2206 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->state != state)
2207 return FALSE;
2210 return TRUE;
2213 static enum object_state session_get_object_state_for_event(MediaEventType event)
2215 switch (event)
2217 case MESourceStarted:
2218 case MEStreamStarted:
2219 case MEStreamSinkStarted:
2220 return OBJ_STATE_STARTED;
2221 case MESourcePaused:
2222 case MEStreamPaused:
2223 case MEStreamSinkPaused:
2224 return OBJ_STATE_PAUSED;
2225 case MESourceStopped:
2226 case MEStreamStopped:
2227 case MEStreamSinkStopped:
2228 return OBJ_STATE_STOPPED;
2229 case MEStreamSinkPrerolled:
2230 return OBJ_STATE_PREROLLED;
2231 default:
2232 return OBJ_STATE_INVALID;
2236 static void session_set_consumed_clock(IUnknown *object, IMFPresentationClock *clock)
2238 IMFClockConsumer *consumer;
2240 if (SUCCEEDED(IUnknown_QueryInterface(object, &IID_IMFClockConsumer, (void **)&consumer)))
2242 IMFClockConsumer_SetPresentationClock(consumer, clock);
2243 IMFClockConsumer_Release(consumer);
2247 static void session_set_presentation_clock(struct media_session *session)
2249 IMFPresentationTimeSource *time_source = NULL;
2250 struct media_source *source;
2251 struct media_sink *sink;
2252 struct topo_node *node;
2253 HRESULT hr;
2255 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2257 if (node->type == MF_TOPOLOGY_TRANSFORM_NODE)
2258 IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
2261 if (!(session->presentation.flags & SESSION_FLAG_PRESENTATION_CLOCK_SET))
2263 /* Attempt to get time source from the sinks. */
2264 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2266 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink->sink, &IID_IMFPresentationTimeSource,
2267 (void **)&time_source)))
2268 break;
2271 if (time_source)
2273 hr = IMFPresentationClock_SetTimeSource(session->clock, time_source);
2274 IMFPresentationTimeSource_Release(time_source);
2276 else
2277 hr = IMFPresentationClock_SetTimeSource(session->clock, session->system_time_source);
2279 if (FAILED(hr))
2280 WARN("Failed to set time source, hr %#x.\n", hr);
2282 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2284 if (node->type != MF_TOPOLOGY_OUTPUT_NODE)
2285 continue;
2287 if (FAILED(hr = IMFStreamSink_BeginGetEvent(node->object.sink_stream, &session->events_callback,
2288 node->object.object)))
2290 WARN("Failed to subscribe to stream sink events, hr %#x.\n", hr);
2294 /* Set clock for all topology nodes. */
2295 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2297 session_set_consumed_clock((IUnknown *)source->source, session->clock);
2300 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2302 if (sink->event_generator && FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(sink->event_generator,
2303 &session->events_callback, (IUnknown *)sink->event_generator)))
2305 WARN("Failed to subscribe to sink events, hr %#x.\n", hr);
2308 if (FAILED(hr = IMFMediaSink_SetPresentationClock(sink->sink, session->clock)))
2309 WARN("Failed to set presentation clock for the sink, hr %#x.\n", hr);
2312 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2314 if (node->type != MF_TOPOLOGY_TRANSFORM_NODE)
2315 continue;
2317 session_set_consumed_clock(node->object.object, session->clock);
2320 session->presentation.flags |= SESSION_FLAG_PRESENTATION_CLOCK_SET;
2324 static HRESULT session_start_clock(struct media_session *session)
2326 LONGLONG start_offset = 0;
2327 HRESULT hr;
2329 if (IsEqualGUID(&session->presentation.time_format, &GUID_NULL))
2331 if (session->presentation.start_position.vt == VT_EMPTY)
2332 start_offset = PRESENTATION_CURRENT_POSITION;
2333 else if (session->presentation.start_position.vt == VT_I8)
2334 start_offset = session->presentation.start_position.hVal.QuadPart;
2335 else
2336 FIXME("Unhandled position type %d.\n", session->presentation.start_position.vt);
2338 else
2339 FIXME("Unhandled time format %s.\n", debugstr_guid(&session->presentation.time_format));
2341 if (FAILED(hr = IMFPresentationClock_Start(session->clock, start_offset)))
2342 WARN("Failed to start session clock, hr %#x.\n", hr);
2344 return hr;
2347 static struct topo_node *session_get_node_object(struct media_session *session, IUnknown *object,
2348 MF_TOPOLOGY_TYPE node_type)
2350 struct topo_node *node = NULL;
2352 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2354 if (node->type == node_type && object == node->object.object)
2355 break;
2358 return node;
2361 static BOOL session_set_node_object_state(struct media_session *session, IUnknown *object,
2362 MF_TOPOLOGY_TYPE node_type, enum object_state state)
2364 struct topo_node *node;
2365 BOOL changed = FALSE;
2367 if ((node = session_get_node_object(session, object, node_type)))
2369 changed = node->state != state;
2370 node->state = state;
2373 return changed;
2376 static void session_set_source_object_state(struct media_session *session, IUnknown *object,
2377 MediaEventType event_type)
2379 IMFStreamSink *stream_sink;
2380 struct media_source *src;
2381 struct media_sink *sink;
2382 enum object_state state;
2383 struct topo_node *node;
2384 unsigned int i, count;
2385 BOOL changed = FALSE;
2386 HRESULT hr;
2388 if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
2389 return;
2391 switch (event_type)
2393 case MESourceStarted:
2394 case MESourcePaused:
2395 case MESourceStopped:
2397 LIST_FOR_EACH_ENTRY(src, &session->presentation.sources, struct media_source, entry)
2399 if (object == (IUnknown *)src->source)
2401 changed = src->state != state;
2402 src->state = state;
2403 break;
2406 break;
2407 case MEStreamStarted:
2408 case MEStreamPaused:
2409 case MEStreamStopped:
2411 changed = session_set_node_object_state(session, object, MF_TOPOLOGY_SOURCESTREAM_NODE, state);
2412 default:
2416 if (!changed)
2417 return;
2419 switch (session->state)
2421 case SESSION_STATE_STARTING_SOURCES:
2422 if (!session_is_source_nodes_state(session, OBJ_STATE_STARTED))
2423 break;
2425 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_STARTED_SOURCE);
2427 session_set_presentation_clock(session);
2429 if (session->presentation.flags & SESSION_FLAG_NEEDS_PREROLL)
2431 MFTIME preroll_time = 0;
2433 if (session->presentation.start_position.vt == VT_I8)
2434 preroll_time = session->presentation.start_position.hVal.QuadPart;
2436 /* Mark stream sinks without prerolling support as PREROLLED to keep state test logic generic. */
2437 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2439 if (sink->preroll)
2441 /* FIXME: abort and enter error state on failure. */
2442 if (FAILED(hr = IMFMediaSinkPreroll_NotifyPreroll(sink->preroll, preroll_time)))
2443 WARN("Preroll notification failed, hr %#x.\n", hr);
2445 else
2447 if (SUCCEEDED(IMFMediaSink_GetStreamSinkCount(sink->sink, &count)))
2449 for (i = 0; i < count; ++i)
2451 if (SUCCEEDED(IMFMediaSink_GetStreamSinkByIndex(sink->sink, i, &stream_sink)))
2453 session_set_node_object_state(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE,
2454 OBJ_STATE_PREROLLED);
2455 IMFStreamSink_Release(stream_sink);
2461 session->state = SESSION_STATE_PREROLLING_SINKS;
2463 else if (SUCCEEDED(session_start_clock(session)))
2464 session->state = SESSION_STATE_STARTING_SINKS;
2466 break;
2467 case SESSION_STATE_PAUSING_SOURCES:
2468 if (!session_is_source_nodes_state(session, OBJ_STATE_PAUSED))
2469 break;
2471 session_set_paused(session, S_OK);
2472 break;
2473 case SESSION_STATE_STOPPING_SOURCES:
2474 if (!session_is_source_nodes_state(session, OBJ_STATE_STOPPED))
2475 break;
2477 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2479 switch (node->type)
2481 case MF_TOPOLOGY_OUTPUT_NODE:
2482 IMFStreamSink_Flush(node->object.sink_stream);
2483 break;
2484 case MF_TOPOLOGY_TRANSFORM_NODE:
2485 IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_COMMAND_FLUSH, 0);
2486 break;
2487 default:
2492 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
2494 if (session->presentation.flags & SESSION_FLAG_FINALIZE_SINKS)
2495 session_finalize_sinks(session);
2496 else
2497 session_set_stopped(session, S_OK);
2499 break;
2500 default:
2505 static void session_set_sink_stream_state(struct media_session *session, IMFStreamSink *stream,
2506 MediaEventType event_type)
2508 struct media_source *source;
2509 enum object_state state;
2510 HRESULT hr = S_OK;
2511 BOOL changed;
2513 if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
2514 return;
2516 if (!(changed = session_set_node_object_state(session, (IUnknown *)stream, MF_TOPOLOGY_OUTPUT_NODE, state)))
2517 return;
2519 switch (session->state)
2521 case SESSION_STATE_PREROLLING_SINKS:
2522 if (!session_is_output_nodes_state(session, OBJ_STATE_PREROLLED))
2523 break;
2525 if (SUCCEEDED(session_start_clock(session)))
2526 session->state = SESSION_STATE_STARTING_SINKS;
2527 break;
2528 case SESSION_STATE_STARTING_SINKS:
2529 if (!session_is_output_nodes_state(session, OBJ_STATE_STARTED))
2530 break;
2532 session_set_started(session);
2533 break;
2534 case SESSION_STATE_PAUSING_SINKS:
2535 if (!session_is_output_nodes_state(session, OBJ_STATE_PAUSED))
2536 break;
2538 session->state = SESSION_STATE_PAUSING_SOURCES;
2540 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2542 if (FAILED(hr = IMFMediaSource_Pause(source->source)))
2543 break;
2546 if (FAILED(hr))
2547 session_set_paused(session, hr);
2549 break;
2550 case SESSION_STATE_STOPPING_SINKS:
2551 if (!session_is_output_nodes_state(session, OBJ_STATE_STOPPED))
2552 break;
2554 session->state = SESSION_STATE_STOPPING_SOURCES;
2556 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2558 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION)
2559 IMFMediaSource_Stop(source->source);
2560 else if (FAILED(hr = IMFMediaSource_Stop(source->source)))
2561 break;
2564 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION || FAILED(hr))
2565 session_set_stopped(session, hr);
2567 break;
2568 default:
2573 static DWORD transform_node_get_stream_id(struct topo_node *node, BOOL output, DWORD index)
2575 unsigned int *map = output ? node->u.transform.output_map : node->u.transform.input_map;
2576 return map ? map[index] : index;
2579 static struct sample *transform_create_sample(IMFSample *sample)
2581 struct sample *sample_entry = heap_alloc_zero(sizeof(*sample_entry));
2583 if (sample_entry)
2585 sample_entry->sample = sample;
2586 if (sample_entry->sample)
2587 IMFSample_AddRef(sample_entry->sample);
2590 return sample_entry;
2593 static HRESULT transform_get_external_output_sample(const struct media_session *session, struct topo_node *transform,
2594 unsigned int output_index, const MFT_OUTPUT_STREAM_INFO *stream_info, IMFSample **sample)
2596 IMFTopologyNode *downstream_node;
2597 unsigned int downstream_input;
2598 IMFMediaBuffer *buffer = NULL;
2599 struct topo_node *topo_node;
2600 TOPOID node_id;
2601 HRESULT hr;
2603 if (FAILED(IMFTopologyNode_GetOutput(transform->node, output_index, &downstream_node, &downstream_input)))
2605 WARN("Failed to get connected node for output %u.\n", output_index);
2606 return MF_E_UNEXPECTED;
2609 IMFTopologyNode_GetTopoNodeID(downstream_node, &node_id);
2610 IMFTopologyNode_Release(downstream_node);
2612 topo_node = session_get_node_by_id(session, node_id);
2614 if (topo_node->type == MF_TOPOLOGY_OUTPUT_NODE && topo_node->u.sink.allocator)
2616 hr = IMFVideoSampleAllocator_AllocateSample(topo_node->u.sink.allocator, sample);
2618 else
2620 hr = MFCreateAlignedMemoryBuffer(stream_info->cbSize, stream_info->cbAlignment, &buffer);
2621 if (SUCCEEDED(hr))
2622 hr = MFCreateSample(sample);
2624 if (SUCCEEDED(hr))
2625 hr = IMFSample_AddBuffer(*sample, buffer);
2627 if (buffer)
2628 IMFMediaBuffer_Release(buffer);
2631 return hr;
2634 static HRESULT transform_node_pull_samples(const struct media_session *session, struct topo_node *node)
2636 MFT_OUTPUT_STREAM_INFO stream_info;
2637 MFT_OUTPUT_DATA_BUFFER *buffers;
2638 struct sample *queued_sample;
2639 DWORD status = 0;
2640 unsigned int i;
2641 HRESULT hr = E_UNEXPECTED;
2643 if (!(buffers = heap_calloc(node->u.transform.output_count, sizeof(*buffers))))
2644 return E_OUTOFMEMORY;
2646 for (i = 0; i < node->u.transform.output_count; ++i)
2648 buffers[i].dwStreamID = transform_node_get_stream_id(node, TRUE, i);
2649 buffers[i].pSample = NULL;
2650 buffers[i].dwStatus = 0;
2651 buffers[i].pEvents = NULL;
2653 memset(&stream_info, 0, sizeof(stream_info));
2654 if (FAILED(hr = IMFTransform_GetOutputStreamInfo(node->object.transform, buffers[i].dwStreamID, &stream_info)))
2655 break;
2657 if (!(stream_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES))
2659 if (FAILED(hr = transform_get_external_output_sample(session, node, i, &stream_info, &buffers[i].pSample)))
2660 break;
2664 if (SUCCEEDED(hr))
2665 hr = IMFTransform_ProcessOutput(node->object.transform, 0, node->u.transform.output_count, buffers, &status);
2667 /* Collect returned samples for all streams. */
2668 for (i = 0; i < node->u.transform.output_count; ++i)
2670 if (buffers[i].pEvents)
2671 IMFCollection_Release(buffers[i].pEvents);
2673 if (SUCCEEDED(hr) && !(buffers[i].dwStatus & MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE))
2675 if (session->quality_manager)
2676 IMFQualityManager_NotifyProcessOutput(session->quality_manager, node->node, i, buffers[i].pSample);
2678 queued_sample = transform_create_sample(buffers[i].pSample);
2679 list_add_tail(&node->u.transform.outputs[i].samples, &queued_sample->entry);
2682 if (buffers[i].pSample)
2683 IMFSample_Release(buffers[i].pSample);
2686 heap_free(buffers);
2688 return hr;
2691 static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input,
2692 IMFSample *sample)
2694 struct sample *sample_entry, *sample_entry2;
2695 DWORD stream_id, downstream_input;
2696 IMFTopologyNode *downstream_node;
2697 struct topo_node *topo_node;
2698 MF_TOPOLOGY_TYPE node_type;
2699 BOOL drain = FALSE;
2700 TOPOID node_id;
2701 unsigned int i;
2702 HRESULT hr;
2704 if (session->quality_manager)
2705 IMFQualityManager_NotifyProcessInput(session->quality_manager, node, input, sample);
2707 IMFTopologyNode_GetNodeType(node, &node_type);
2708 IMFTopologyNode_GetTopoNodeID(node, &node_id);
2710 topo_node = session_get_node_by_id(session, node_id);
2712 switch (node_type)
2714 case MF_TOPOLOGY_OUTPUT_NODE:
2715 if (sample)
2717 if (topo_node->u.sink.requests)
2719 if (FAILED(hr = IMFStreamSink_ProcessSample(topo_node->object.sink_stream, sample)))
2720 WARN("Stream sink failed to process sample, hr %#x.\n", hr);
2721 topo_node->u.sink.requests--;
2724 else if (FAILED(hr = IMFStreamSink_PlaceMarker(topo_node->object.sink_stream, MFSTREAMSINK_MARKER_ENDOFSEGMENT,
2725 NULL, NULL)))
2727 WARN("Failed to place sink marker, hr %#x.\n", hr);
2729 break;
2730 case MF_TOPOLOGY_TRANSFORM_NODE:
2732 transform_node_pull_samples(session, topo_node);
2734 sample_entry = transform_create_sample(sample);
2735 list_add_tail(&topo_node->u.transform.inputs[input].samples, &sample_entry->entry);
2737 for (i = 0; i < topo_node->u.transform.input_count; ++i)
2739 stream_id = transform_node_get_stream_id(topo_node, FALSE, i);
2740 LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.inputs[i].samples,
2741 struct sample, entry)
2743 if (sample_entry->sample)
2745 if ((hr = IMFTransform_ProcessInput(topo_node->object.transform, stream_id,
2746 sample_entry->sample, 0)) == MF_E_NOTACCEPTING)
2747 break;
2748 if (FAILED(hr))
2749 WARN("Failed to process input for stream %u/%u, hr %#x.\n", i, stream_id, hr);
2750 transform_release_sample(sample_entry);
2752 else
2754 transform_stream_drop_samples(&topo_node->u.transform.inputs[i]);
2755 drain = TRUE;
2760 if (drain)
2762 if (FAILED(hr = IMFTransform_ProcessMessage(topo_node->object.transform, MFT_MESSAGE_COMMAND_DRAIN, 0)))
2763 WARN("Drain command failed for transform, hr %#x.\n", hr);
2766 transform_node_pull_samples(session, topo_node);
2768 /* Remaining unprocessed input has been discarded, now queue markers for every output. */
2769 if (drain)
2771 for (i = 0; i < topo_node->u.transform.output_count; ++i)
2773 if ((sample_entry = transform_create_sample(NULL)))
2774 list_add_tail(&topo_node->u.transform.outputs[i].samples, &sample_entry->entry);
2778 /* Push down all available output. */
2779 for (i = 0; i < topo_node->u.transform.output_count; ++i)
2781 if (FAILED(IMFTopologyNode_GetOutput(node, i, &downstream_node, &downstream_input)))
2783 WARN("Failed to get connected node for output %u.\n", i);
2784 continue;
2787 LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.outputs[i].samples,
2788 struct sample, entry)
2790 if (!topo_node->u.transform.outputs[i].requests)
2791 break;
2793 session_deliver_sample_to_node(session, downstream_node, downstream_input, sample_entry->sample);
2794 topo_node->u.transform.outputs[i].requests--;
2796 transform_release_sample(sample_entry);
2799 IMFTopologyNode_Release(downstream_node);
2802 break;
2803 case MF_TOPOLOGY_TEE_NODE:
2804 FIXME("Unhandled downstream node type %d.\n", node_type);
2805 break;
2806 default:
2811 static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output)
2813 IMFTopologyNode *downstream_node, *upstream_node;
2814 unsigned int downstream_input, upstream_output;
2815 struct topo_node *topo_node;
2816 MF_TOPOLOGY_TYPE node_type;
2817 struct sample *sample;
2818 TOPOID node_id;
2819 HRESULT hr;
2821 IMFTopologyNode_GetNodeType(node, &node_type);
2822 IMFTopologyNode_GetTopoNodeID(node, &node_id);
2824 topo_node = session_get_node_by_id(session, node_id);
2826 switch (node_type)
2828 case MF_TOPOLOGY_SOURCESTREAM_NODE:
2829 if (FAILED(hr = IMFMediaStream_RequestSample(topo_node->object.source_stream, NULL)))
2830 WARN("Sample request failed, hr %#x.\n", hr);
2831 break;
2832 case MF_TOPOLOGY_TRANSFORM_NODE:
2834 if (list_empty(&topo_node->u.transform.outputs[output].samples))
2836 /* Forward request to upstream node. */
2837 if (SUCCEEDED(hr = IMFTopologyNode_GetInput(node, 0 /* FIXME */, &upstream_node, &upstream_output)))
2839 if (SUCCEEDED(hr = session_request_sample_from_node(session, upstream_node, upstream_output)))
2840 topo_node->u.transform.outputs[output].requests++;
2841 IMFTopologyNode_Release(upstream_node);
2844 else
2846 if (SUCCEEDED(hr = IMFTopologyNode_GetOutput(node, output, &downstream_node, &downstream_input)))
2848 sample = LIST_ENTRY(list_head(&topo_node->u.transform.outputs[output].samples), struct sample, entry);
2849 session_deliver_sample_to_node(session, downstream_node, downstream_input, sample->sample);
2850 transform_release_sample(sample);
2851 IMFTopologyNode_Release(downstream_node);
2855 break;
2856 case MF_TOPOLOGY_TEE_NODE:
2857 FIXME("Unhandled upstream node type %d.\n", node_type);
2858 default:
2859 hr = E_UNEXPECTED;
2862 return hr;
2865 static void session_request_sample(struct media_session *session, IMFStreamSink *sink_stream)
2867 struct topo_node *sink_node = NULL, *node;
2868 IMFTopologyNode *upstream_node;
2869 DWORD upstream_output;
2870 HRESULT hr;
2872 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2874 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink_stream)
2876 sink_node = node;
2877 break;
2881 if (!sink_node)
2882 return;
2884 if (FAILED(hr = IMFTopologyNode_GetInput(sink_node->node, 0, &upstream_node, &upstream_output)))
2886 WARN("Failed to get upstream node connection, hr %#x.\n", hr);
2887 return;
2890 if (SUCCEEDED(session_request_sample_from_node(session, upstream_node, upstream_output)))
2891 sink_node->u.sink.requests++;
2892 IMFTopologyNode_Release(upstream_node);
2895 static void session_deliver_sample(struct media_session *session, IMFMediaStream *stream, const PROPVARIANT *value)
2897 struct topo_node *source_node = NULL, *node;
2898 IMFTopologyNode *downstream_node;
2899 DWORD downstream_input;
2900 HRESULT hr;
2902 if (value && (value->vt != VT_UNKNOWN || !value->punkVal))
2904 WARN("Unexpected value type %d.\n", value->vt);
2905 return;
2908 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2910 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->object.source_stream == stream)
2912 source_node = node;
2913 break;
2917 if (!source_node)
2918 return;
2920 if (!value)
2921 source_node->flags |= TOPO_NODE_END_OF_STREAM;
2923 if (FAILED(hr = IMFTopologyNode_GetOutput(source_node->node, 0, &downstream_node, &downstream_input)))
2925 WARN("Failed to get downstream node connection, hr %#x.\n", hr);
2926 return;
2929 session_deliver_sample_to_node(session, downstream_node, downstream_input, value ? (IMFSample *)value->punkVal : NULL);
2930 IMFTopologyNode_Release(downstream_node);
2933 static void session_sink_invalidated(struct media_session *session, IMFMediaEvent *event, IMFStreamSink *sink)
2935 struct topo_node *node, *sink_node = NULL;
2936 HRESULT hr;
2938 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2940 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink)
2942 sink_node = node;
2943 break;
2947 if (!sink_node)
2948 return;
2950 if (!event)
2952 if (FAILED(hr = MFCreateMediaEvent(MESinkInvalidated, &GUID_NULL, S_OK, NULL, &event)))
2953 WARN("Failed to create event, hr %#x.\n", hr);
2956 if (!event)
2957 return;
2959 IMFMediaEvent_SetUINT64(event, &MF_EVENT_OUTPUT_NODE, sink_node->node_id);
2960 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
2962 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED);
2965 static BOOL session_nodes_is_mask_set(struct media_session *session, MF_TOPOLOGY_TYPE node_type, unsigned int flags)
2967 struct media_source *source;
2968 struct topo_node *node;
2970 if (node_type == MF_TOPOLOGY_MAX)
2972 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2974 if ((source->flags & flags) != flags)
2975 return FALSE;
2978 else
2980 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2982 if (node->type == node_type && (node->flags & flags) != flags)
2983 return FALSE;
2987 return TRUE;
2990 static void session_raise_end_of_presentation(struct media_session *session)
2992 if (!(session_nodes_is_mask_set(session, MF_TOPOLOGY_SOURCESTREAM_NODE, TOPO_NODE_END_OF_STREAM)))
2993 return;
2995 if (!(session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION))
2997 if (session_nodes_is_mask_set(session, MF_TOPOLOGY_MAX, SOURCE_FLAG_END_OF_PRESENTATION))
2999 session->presentation.flags |= SESSION_FLAG_END_OF_PRESENTATION;
3000 session_push_back_command(session, SESSION_CMD_END);
3001 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, NULL);
3006 static void session_handle_end_of_stream(struct media_session *session, IMFMediaStream *stream)
3008 struct topo_node *node;
3010 if (!(node = session_get_node_object(session, (IUnknown *)stream, MF_TOPOLOGY_SOURCESTREAM_NODE))
3011 || node->flags & TOPO_NODE_END_OF_STREAM)
3013 return;
3016 session_deliver_sample(session, stream, NULL);
3018 session_raise_end_of_presentation(session);
3021 static void session_handle_end_of_presentation(struct media_session *session, IMFMediaSource *object)
3023 struct media_source *source;
3025 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3027 if (source->source == object)
3029 if (!(source->flags & SOURCE_FLAG_END_OF_PRESENTATION))
3031 source->flags |= SOURCE_FLAG_END_OF_PRESENTATION;
3032 session_raise_end_of_presentation(session);
3035 break;
3040 static void session_sink_stream_marker(struct media_session *session, IMFStreamSink *stream_sink)
3042 struct topo_node *node;
3044 if (!(node = session_get_node_object(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE))
3045 || node->flags & TOPO_NODE_END_OF_STREAM)
3047 return;
3050 node->flags |= TOPO_NODE_END_OF_STREAM;
3052 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION &&
3053 session_nodes_is_mask_set(session, MF_TOPOLOGY_OUTPUT_NODE, TOPO_NODE_END_OF_STREAM))
3055 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED);
3056 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
3057 session_stop(session);
3061 static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
3063 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
3064 IMFMediaEventGenerator *event_source;
3065 IMFMediaEvent *event = NULL;
3066 MediaEventType event_type;
3067 IUnknown *object = NULL;
3068 IMFMediaSource *source;
3069 IMFMediaStream *stream;
3070 PROPVARIANT value;
3071 HRESULT hr;
3073 if (FAILED(hr = IMFAsyncResult_GetState(result, (IUnknown **)&event_source)))
3074 return hr;
3076 if (FAILED(hr = IMFMediaEventGenerator_EndGetEvent(event_source, result, &event)))
3078 WARN("Failed to get event from %p, hr %#x.\n", event_source, hr);
3079 goto failed;
3082 if (FAILED(hr = IMFMediaEvent_GetType(event, &event_type)))
3084 WARN("Failed to get event type, hr %#x.\n", hr);
3085 goto failed;
3088 value.vt = VT_EMPTY;
3089 if (FAILED(hr = IMFMediaEvent_GetValue(event, &value)))
3091 WARN("Failed to get event value, hr %#x.\n", hr);
3092 goto failed;
3095 switch (event_type)
3097 case MESourceStarted:
3098 case MESourcePaused:
3099 case MESourceStopped:
3100 case MEStreamStarted:
3101 case MEStreamPaused:
3102 case MEStreamStopped:
3104 EnterCriticalSection(&session->cs);
3105 session_set_source_object_state(session, (IUnknown *)event_source, event_type);
3106 LeaveCriticalSection(&session->cs);
3108 break;
3110 case MEBufferingStarted:
3111 case MEBufferingStopped:
3113 EnterCriticalSection(&session->cs);
3114 if (session_get_media_source(session, (IMFMediaSource *)event_source))
3116 if (event_type == MEBufferingStarted)
3117 IMFPresentationClock_Pause(session->clock);
3118 else
3119 IMFPresentationClock_Start(session->clock, PRESENTATION_CURRENT_POSITION);
3121 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3123 LeaveCriticalSection(&session->cs);
3124 break;
3126 case MENewStream:
3127 stream = (IMFMediaStream *)value.punkVal;
3129 if (value.vt != VT_UNKNOWN || !stream)
3131 WARN("Unexpected event value.\n");
3132 break;
3135 if (FAILED(hr = IMFMediaStream_GetMediaSource(stream, &source)))
3136 break;
3138 EnterCriticalSection(&session->cs);
3139 if (SUCCEEDED(hr = session_add_media_stream(session, source, stream)))
3140 hr = IMFMediaStream_BeginGetEvent(stream, &session->events_callback, (IUnknown *)stream);
3141 LeaveCriticalSection(&session->cs);
3143 IMFMediaSource_Release(source);
3145 break;
3146 case MEStreamSinkStarted:
3147 case MEStreamSinkPaused:
3148 case MEStreamSinkStopped:
3149 case MEStreamSinkPrerolled:
3151 EnterCriticalSection(&session->cs);
3152 session_set_sink_stream_state(session, (IMFStreamSink *)event_source, event_type);
3153 LeaveCriticalSection(&session->cs);
3155 break;
3156 case MEStreamSinkMarker:
3158 EnterCriticalSection(&session->cs);
3159 session_sink_stream_marker(session, (IMFStreamSink *)event_source);
3160 LeaveCriticalSection(&session->cs);
3162 break;
3163 case MEStreamSinkRequestSample:
3165 EnterCriticalSection(&session->cs);
3166 session_request_sample(session, (IMFStreamSink *)event_source);
3167 LeaveCriticalSection(&session->cs);
3169 break;
3170 case MEMediaSample:
3172 EnterCriticalSection(&session->cs);
3173 session_deliver_sample(session, (IMFMediaStream *)event_source, &value);
3174 LeaveCriticalSection(&session->cs);
3176 break;
3177 case MEEndOfStream:
3179 EnterCriticalSection(&session->cs);
3180 session_handle_end_of_stream(session, (IMFMediaStream *)event_source);
3181 LeaveCriticalSection(&session->cs);
3183 break;
3185 case MEEndOfPresentation:
3187 EnterCriticalSection(&session->cs);
3188 session_handle_end_of_presentation(session, (IMFMediaSource *)event_source);
3189 LeaveCriticalSection(&session->cs);
3191 break;
3192 case MEAudioSessionGroupingParamChanged:
3193 case MEAudioSessionIconChanged:
3194 case MEAudioSessionNameChanged:
3195 case MEAudioSessionVolumeChanged:
3197 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3199 break;
3200 case MEAudioSessionDeviceRemoved:
3201 case MEAudioSessionDisconnected:
3202 case MEAudioSessionExclusiveModeOverride:
3203 case MEAudioSessionFormatChanged:
3204 case MEAudioSessionServerShutdown:
3206 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3207 /* fallthrough */
3208 case MESinkInvalidated:
3210 EnterCriticalSection(&session->cs);
3211 session_sink_invalidated(session, event_type == MESinkInvalidated ? event : NULL,
3212 (IMFStreamSink *)event_source);
3213 LeaveCriticalSection(&session->cs);
3215 break;
3216 case MEQualityNotify:
3218 if (session->quality_manager)
3220 if (FAILED(IMFMediaEventGenerator_QueryInterface(event_source, &IID_IMFStreamSink, (void **)&object)))
3221 IMFMediaEventGenerator_QueryInterface(event_source, &IID_IMFTransform, (void **)&object);
3223 if (object)
3225 IMFQualityManager_NotifyQualityEvent(session->quality_manager, object, event);
3226 IUnknown_Release(object);
3230 break;
3231 default:
3235 PropVariantClear(&value);
3237 failed:
3238 if (event)
3239 IMFMediaEvent_Release(event);
3241 if (FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(event_source, iface, (IUnknown *)event_source)))
3242 WARN("Failed to re-subscribe, hr %#x.\n", hr);
3244 IMFMediaEventGenerator_Release(event_source);
3246 return hr;
3249 static const IMFAsyncCallbackVtbl session_events_callback_vtbl =
3251 session_events_callback_QueryInterface,
3252 session_events_callback_AddRef,
3253 session_events_callback_Release,
3254 session_events_callback_GetParameters,
3255 session_events_callback_Invoke,
3258 static HRESULT WINAPI session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
3260 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
3261 IsEqualIID(riid, &IID_IUnknown))
3263 *obj = iface;
3264 IMFAsyncCallback_AddRef(iface);
3265 return S_OK;
3268 WARN("Unsupported %s.\n", debugstr_guid(riid));
3269 *obj = NULL;
3270 return E_NOINTERFACE;
3273 static ULONG WINAPI session_sink_finalizer_callback_AddRef(IMFAsyncCallback *iface)
3275 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3276 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3279 static ULONG WINAPI session_sink_finalizer_callback_Release(IMFAsyncCallback *iface)
3281 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3282 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3285 static HRESULT WINAPI session_sink_finalizer_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
3287 return E_NOTIMPL;
3290 static HRESULT WINAPI session_sink_finalizer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
3292 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3293 IMFFinalizableMediaSink *fin_sink = NULL;
3294 BOOL sinks_finalized = TRUE;
3295 struct media_sink *sink;
3296 IUnknown *state;
3297 HRESULT hr;
3299 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
3300 return hr;
3302 EnterCriticalSection(&session->cs);
3304 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
3306 if (state == (IUnknown *)sink->sink)
3308 if (FAILED(hr = IMFMediaSink_QueryInterface(sink->sink, &IID_IMFFinalizableMediaSink, (void **)&fin_sink)))
3309 WARN("Unexpected, missing IMFFinalizableSink, hr %#x.\n", hr);
3311 else
3313 sinks_finalized &= sink->finalized;
3314 if (!sinks_finalized)
3315 break;
3319 IUnknown_Release(state);
3321 if (fin_sink)
3323 /* Complete session transition, or close prematurely on error. */
3324 if (SUCCEEDED(hr = IMFFinalizableMediaSink_EndFinalize(fin_sink, result)))
3326 sink->finalized = TRUE;
3327 if (sinks_finalized)
3328 session_set_closed(session, hr);
3330 IMFFinalizableMediaSink_Release(fin_sink);
3333 LeaveCriticalSection(&session->cs);
3335 return S_OK;
3338 static const IMFAsyncCallbackVtbl session_sink_finalizer_callback_vtbl =
3340 session_sink_finalizer_callback_QueryInterface,
3341 session_sink_finalizer_callback_AddRef,
3342 session_sink_finalizer_callback_Release,
3343 session_sink_finalizer_callback_GetParameters,
3344 session_sink_finalizer_callback_Invoke,
3347 static HRESULT WINAPI session_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
3349 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3350 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
3353 static ULONG WINAPI session_rate_support_AddRef(IMFRateSupport *iface)
3355 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3356 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3359 static ULONG WINAPI session_rate_support_Release(IMFRateSupport *iface)
3361 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3362 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3365 static HRESULT session_presentation_object_get_rate(IUnknown *object, MFRATE_DIRECTION direction,
3366 BOOL thin, BOOL fastest, float *result)
3368 IMFRateSupport *rate_support;
3369 float rate;
3370 HRESULT hr;
3372 /* For objects that don't support rate control, it's assumed that only forward direction is allowed, at 1.0f. */
3374 if (FAILED(hr = MFGetService(object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support)))
3376 if (direction == MFRATE_FORWARD)
3378 *result = 1.0f;
3379 return S_OK;
3381 else
3382 return MF_E_REVERSE_UNSUPPORTED;
3385 rate = 0.0f;
3386 if (fastest)
3388 if (SUCCEEDED(hr = IMFRateSupport_GetFastestRate(rate_support, direction, thin, &rate)))
3389 *result = min(fabsf(rate), *result);
3391 else
3393 if (SUCCEEDED(hr = IMFRateSupport_GetSlowestRate(rate_support, direction, thin, &rate)))
3394 *result = max(fabsf(rate), *result);
3397 IMFRateSupport_Release(rate_support);
3399 return hr;
3402 static HRESULT session_get_presentation_rate(struct media_session *session, MFRATE_DIRECTION direction,
3403 BOOL thin, BOOL fastest, float *result)
3405 struct media_source *source;
3406 struct media_sink *sink;
3407 HRESULT hr = E_POINTER;
3409 *result = 0.0f;
3411 EnterCriticalSection(&session->cs);
3413 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
3415 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3417 if (FAILED(hr = session_presentation_object_get_rate((IUnknown *)source->source, direction, thin, fastest, result)))
3418 break;
3421 if (SUCCEEDED(hr))
3423 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
3425 if (FAILED(hr = session_presentation_object_get_rate((IUnknown *)sink->sink, direction, thin, fastest, result)))
3426 break;
3431 LeaveCriticalSection(&session->cs);
3433 return hr;
3436 static HRESULT WINAPI session_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
3437 BOOL thin, float *rate)
3439 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3441 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
3443 return session_get_presentation_rate(session, direction, thin, FALSE, rate);
3446 static HRESULT WINAPI session_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
3447 BOOL thin, float *rate)
3449 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3451 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
3453 return session_get_presentation_rate(session, direction, thin, TRUE, rate);
3456 static HRESULT WINAPI session_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
3457 float *nearest_supported_rate)
3459 FIXME("%p, %d, %f, %p.\n", iface, thin, rate, nearest_supported_rate);
3461 return E_NOTIMPL;
3464 static const IMFRateSupportVtbl session_rate_support_vtbl =
3466 session_rate_support_QueryInterface,
3467 session_rate_support_AddRef,
3468 session_rate_support_Release,
3469 session_rate_support_GetSlowestRate,
3470 session_rate_support_GetFastestRate,
3471 session_rate_support_IsRateSupported,
3474 static HRESULT WINAPI session_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj)
3476 struct media_session *session = impl_session_from_IMFRateControl(iface);
3477 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
3480 static ULONG WINAPI session_rate_control_AddRef(IMFRateControl *iface)
3482 struct media_session *session = impl_session_from_IMFRateControl(iface);
3483 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3486 static ULONG WINAPI session_rate_control_Release(IMFRateControl *iface)
3488 struct media_session *session = impl_session_from_IMFRateControl(iface);
3489 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3492 static HRESULT WINAPI session_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate)
3494 FIXME("%p, %d, %f.\n", iface, thin, rate);
3496 return E_NOTIMPL;
3499 static HRESULT WINAPI session_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
3501 struct media_session *session = impl_session_from_IMFRateControl(iface);
3503 TRACE("%p, %p, %p.\n", iface, thin, rate);
3505 return IMFRateControl_GetRate(session->clock_rate_control, thin, rate);
3508 static const IMFRateControlVtbl session_rate_control_vtbl =
3510 session_rate_control_QueryInterface,
3511 session_rate_control_AddRef,
3512 session_rate_control_Release,
3513 session_rate_control_SetRate,
3514 session_rate_control_GetRate,
3517 /***********************************************************************
3518 * MFCreateMediaSession (mf.@)
3520 HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **session)
3522 BOOL without_quality_manager = FALSE;
3523 struct media_session *object;
3524 HRESULT hr;
3526 TRACE("%p, %p.\n", config, session);
3528 object = heap_alloc_zero(sizeof(*object));
3529 if (!object)
3530 return E_OUTOFMEMORY;
3532 object->IMFMediaSession_iface.lpVtbl = &mfmediasessionvtbl;
3533 object->IMFGetService_iface.lpVtbl = &session_get_service_vtbl;
3534 object->IMFRateSupport_iface.lpVtbl = &session_rate_support_vtbl;
3535 object->IMFRateControl_iface.lpVtbl = &session_rate_control_vtbl;
3536 object->commands_callback.lpVtbl = &session_commands_callback_vtbl;
3537 object->events_callback.lpVtbl = &session_events_callback_vtbl;
3538 object->sink_finalizer_callback.lpVtbl = &session_sink_finalizer_callback_vtbl;
3539 object->refcount = 1;
3540 list_init(&object->topologies);
3541 list_init(&object->commands);
3542 list_init(&object->presentation.sources);
3543 list_init(&object->presentation.sinks);
3544 list_init(&object->presentation.nodes);
3545 InitializeCriticalSection(&object->cs);
3547 if (FAILED(hr = MFCreateTopology(&object->presentation.current_topology)))
3548 goto failed;
3550 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
3551 goto failed;
3553 if (FAILED(hr = MFCreatePresentationClock(&object->clock)))
3554 goto failed;
3556 if (FAILED(hr = MFCreateSystemTimeSource(&object->system_time_source)))
3557 goto failed;
3559 if (FAILED(hr = IMFPresentationClock_QueryInterface(object->clock, &IID_IMFRateControl,
3560 (void **)&object->clock_rate_control)))
3562 goto failed;
3565 if (config)
3567 GUID clsid;
3569 if (SUCCEEDED(IMFAttributes_GetGUID(config, &MF_SESSION_TOPOLOADER, &clsid)))
3571 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTopoLoader,
3572 (void **)&object->topo_loader)))
3574 WARN("Failed to create custom topology loader, hr %#x.\n", hr);
3578 if (SUCCEEDED(IMFAttributes_GetGUID(config, &MF_SESSION_QUALITY_MANAGER, &clsid)))
3580 if (!(without_quality_manager = IsEqualGUID(&clsid, &GUID_NULL)))
3582 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFQualityManager,
3583 (void **)&object->quality_manager)))
3585 WARN("Failed to create custom quality manager, hr %#x.\n", hr);
3591 if (!object->topo_loader && FAILED(hr = MFCreateTopoLoader(&object->topo_loader)))
3592 goto failed;
3594 if (!object->quality_manager && !without_quality_manager &&
3595 FAILED(hr = MFCreateStandardQualityManager(&object->quality_manager)))
3597 goto failed;
3600 if (object->quality_manager && FAILED(hr = IMFQualityManager_NotifyPresentationClock(object->quality_manager,
3601 object->clock)))
3603 goto failed;
3606 *session = &object->IMFMediaSession_iface;
3608 return S_OK;
3610 failed:
3611 IMFMediaSession_Release(&object->IMFMediaSession_iface);
3612 return hr;
3615 static HRESULT WINAPI sink_notification_QueryInterface(IUnknown *iface, REFIID riid, void **out)
3617 if (IsEqualIID(riid, &IID_IUnknown))
3619 *out = iface;
3620 IUnknown_AddRef(iface);
3621 return S_OK;
3624 WARN("Unsupported %s.\n", debugstr_guid(riid));
3625 *out = NULL;
3626 return E_NOINTERFACE;
3629 static ULONG WINAPI sink_notification_AddRef(IUnknown *iface)
3631 struct sink_notification *notification = impl_sink_notification_from_IUnknown(iface);
3632 ULONG refcount = InterlockedIncrement(&notification->refcount);
3634 TRACE("%p, refcount %u.\n", iface, refcount);
3636 return refcount;
3639 static ULONG WINAPI sink_notification_Release(IUnknown *iface)
3641 struct sink_notification *notification = impl_sink_notification_from_IUnknown(iface);
3642 ULONG refcount = InterlockedDecrement(&notification->refcount);
3644 TRACE("%p, refcount %u.\n", iface, refcount);
3646 if (!refcount)
3648 IMFClockStateSink_Release(notification->sink);
3649 heap_free(notification);
3652 return refcount;
3655 static const IUnknownVtbl sinknotificationvtbl =
3657 sink_notification_QueryInterface,
3658 sink_notification_AddRef,
3659 sink_notification_Release,
3662 static void clock_notify_async_sink(struct presentation_clock *clock, MFTIME system_time,
3663 struct clock_state_change_param param, enum clock_notification notification, IMFClockStateSink *sink)
3665 struct sink_notification *object;
3666 IMFAsyncResult *result;
3667 HRESULT hr;
3669 object = heap_alloc(sizeof(*object));
3670 if (!object)
3671 return;
3673 object->IUnknown_iface.lpVtbl = &sinknotificationvtbl;
3674 object->refcount = 1;
3675 object->system_time = system_time;
3676 object->param = param;
3677 object->notification = notification;
3678 object->sink = sink;
3679 IMFClockStateSink_AddRef(object->sink);
3681 hr = MFCreateAsyncResult(&object->IUnknown_iface, &clock->sink_callback, NULL, &result);
3682 IUnknown_Release(&object->IUnknown_iface);
3683 if (SUCCEEDED(hr))
3685 MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD, result);
3686 IMFAsyncResult_Release(result);
3690 static HRESULT WINAPI present_clock_QueryInterface(IMFPresentationClock *iface, REFIID riid, void **out)
3692 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3694 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
3696 if (IsEqualIID(riid, &IID_IMFPresentationClock) ||
3697 IsEqualIID(riid, &IID_IMFClock) ||
3698 IsEqualIID(riid, &IID_IUnknown))
3700 *out = &clock->IMFPresentationClock_iface;
3702 else if (IsEqualIID(riid, &IID_IMFRateControl))
3704 *out = &clock->IMFRateControl_iface;
3706 else if (IsEqualIID(riid, &IID_IMFTimer))
3708 *out = &clock->IMFTimer_iface;
3710 else if (IsEqualIID(riid, &IID_IMFShutdown))
3712 *out = &clock->IMFShutdown_iface;
3714 else
3716 WARN("Unsupported %s.\n", debugstr_guid(riid));
3717 *out = NULL;
3718 return E_NOINTERFACE;
3721 IUnknown_AddRef((IUnknown *)*out);
3722 return S_OK;
3725 static ULONG WINAPI present_clock_AddRef(IMFPresentationClock *iface)
3727 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3728 ULONG refcount = InterlockedIncrement(&clock->refcount);
3730 TRACE("%p, refcount %u.\n", iface, refcount);
3732 return refcount;
3735 static ULONG WINAPI present_clock_Release(IMFPresentationClock *iface)
3737 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3738 ULONG refcount = InterlockedDecrement(&clock->refcount);
3739 struct clock_timer *timer, *timer2;
3740 struct clock_sink *sink, *sink2;
3742 TRACE("%p, refcount %u.\n", iface, refcount);
3744 if (!refcount)
3746 if (clock->time_source)
3747 IMFPresentationTimeSource_Release(clock->time_source);
3748 if (clock->time_source_sink)
3749 IMFClockStateSink_Release(clock->time_source_sink);
3750 LIST_FOR_EACH_ENTRY_SAFE(sink, sink2, &clock->sinks, struct clock_sink, entry)
3752 list_remove(&sink->entry);
3753 IMFClockStateSink_Release(sink->state_sink);
3754 heap_free(sink);
3756 LIST_FOR_EACH_ENTRY_SAFE(timer, timer2, &clock->timers, struct clock_timer, entry)
3758 list_remove(&timer->entry);
3759 IUnknown_Release(&timer->IUnknown_iface);
3761 DeleteCriticalSection(&clock->cs);
3762 heap_free(clock);
3765 return refcount;
3768 static HRESULT WINAPI present_clock_GetClockCharacteristics(IMFPresentationClock *iface, DWORD *flags)
3770 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3771 HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
3773 TRACE("%p, %p.\n", iface, flags);
3775 EnterCriticalSection(&clock->cs);
3776 if (clock->time_source)
3777 hr = IMFPresentationTimeSource_GetClockCharacteristics(clock->time_source, flags);
3778 LeaveCriticalSection(&clock->cs);
3780 return hr;
3783 static HRESULT WINAPI present_clock_GetCorrelatedTime(IMFPresentationClock *iface, DWORD reserved,
3784 LONGLONG *clock_time, MFTIME *system_time)
3786 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3787 HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
3789 TRACE("%p, %#x, %p, %p.\n", iface, reserved, clock_time, system_time);
3791 EnterCriticalSection(&clock->cs);
3792 if (clock->time_source)
3793 hr = IMFPresentationTimeSource_GetCorrelatedTime(clock->time_source, reserved, clock_time, system_time);
3794 LeaveCriticalSection(&clock->cs);
3796 return hr;
3799 static HRESULT WINAPI present_clock_GetContinuityKey(IMFPresentationClock *iface, DWORD *key)
3801 TRACE("%p, %p.\n", iface, key);
3803 *key = 0;
3805 return S_OK;
3808 static HRESULT WINAPI present_clock_GetState(IMFPresentationClock *iface, DWORD reserved, MFCLOCK_STATE *state)
3810 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3812 TRACE("%p, %#x, %p.\n", iface, reserved, state);
3814 EnterCriticalSection(&clock->cs);
3815 *state = clock->state;
3816 LeaveCriticalSection(&clock->cs);
3818 return S_OK;
3821 static HRESULT WINAPI present_clock_GetProperties(IMFPresentationClock *iface, MFCLOCK_PROPERTIES *props)
3823 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3824 HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
3826 TRACE("%p, %p.\n", iface, props);
3828 EnterCriticalSection(&clock->cs);
3829 if (clock->time_source)
3830 hr = IMFPresentationTimeSource_GetProperties(clock->time_source, props);
3831 LeaveCriticalSection(&clock->cs);
3833 return hr;
3836 static HRESULT WINAPI present_clock_SetTimeSource(IMFPresentationClock *iface,
3837 IMFPresentationTimeSource *time_source)
3839 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3840 MFCLOCK_PROPERTIES props;
3841 IMFClock *source_clock;
3842 HRESULT hr;
3844 TRACE("%p, %p.\n", iface, time_source);
3846 EnterCriticalSection(&clock->cs);
3848 if (clock->time_source)
3849 IMFPresentationTimeSource_Release(clock->time_source);
3850 if (clock->time_source_sink)
3851 IMFClockStateSink_Release(clock->time_source_sink);
3852 clock->time_source = NULL;
3853 clock->time_source_sink = NULL;
3855 hr = IMFPresentationTimeSource_QueryInterface(time_source, &IID_IMFClockStateSink, (void **)&clock->time_source_sink);
3856 if (SUCCEEDED(hr))
3858 clock->time_source = time_source;
3859 IMFPresentationTimeSource_AddRef(clock->time_source);
3862 if (SUCCEEDED(IMFPresentationTimeSource_GetUnderlyingClock(time_source, &source_clock)))
3864 if (SUCCEEDED(IMFClock_GetProperties(source_clock, &props)))
3865 clock->frequency = props.qwClockFrequency;
3866 IMFClock_Release(source_clock);
3869 if (!clock->frequency)
3870 clock->frequency = MFCLOCK_FREQUENCY_HNS;
3872 LeaveCriticalSection(&clock->cs);
3874 return hr;
3877 static HRESULT WINAPI present_clock_GetTimeSource(IMFPresentationClock *iface,
3878 IMFPresentationTimeSource **time_source)
3880 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3881 HRESULT hr = S_OK;
3883 TRACE("%p, %p.\n", iface, time_source);
3885 if (!time_source)
3886 return E_INVALIDARG;
3888 EnterCriticalSection(&clock->cs);
3889 if (clock->time_source)
3891 *time_source = clock->time_source;
3892 IMFPresentationTimeSource_AddRef(*time_source);
3894 else
3895 hr = MF_E_CLOCK_NO_TIME_SOURCE;
3896 LeaveCriticalSection(&clock->cs);
3898 return hr;
3901 static HRESULT WINAPI present_clock_GetTime(IMFPresentationClock *iface, MFTIME *time)
3903 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3904 HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
3905 MFTIME systime;
3907 TRACE("%p, %p.\n", iface, time);
3909 if (!time)
3910 return E_POINTER;
3912 EnterCriticalSection(&clock->cs);
3913 if (clock->time_source)
3914 hr = IMFPresentationTimeSource_GetCorrelatedTime(clock->time_source, 0, time, &systime);
3915 LeaveCriticalSection(&clock->cs);
3917 return hr;
3920 static HRESULT WINAPI present_clock_AddClockStateSink(IMFPresentationClock *iface, IMFClockStateSink *state_sink)
3922 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3923 struct clock_sink *sink, *cur;
3924 HRESULT hr = S_OK;
3926 TRACE("%p, %p.\n", iface, state_sink);
3928 if (!state_sink)
3929 return E_INVALIDARG;
3931 sink = heap_alloc(sizeof(*sink));
3932 if (!sink)
3933 return E_OUTOFMEMORY;
3935 sink->state_sink = state_sink;
3936 IMFClockStateSink_AddRef(sink->state_sink);
3938 EnterCriticalSection(&clock->cs);
3939 LIST_FOR_EACH_ENTRY(cur, &clock->sinks, struct clock_sink, entry)
3941 if (cur->state_sink == state_sink)
3943 hr = E_INVALIDARG;
3944 break;
3947 if (SUCCEEDED(hr))
3949 static const enum clock_notification notifications[MFCLOCK_STATE_PAUSED + 1] =
3951 /* MFCLOCK_STATE_INVALID */ 0, /* Does not apply */
3952 /* MFCLOCK_STATE_RUNNING */ CLOCK_NOTIFY_START,
3953 /* MFCLOCK_STATE_STOPPED */ CLOCK_NOTIFY_STOP,
3954 /* MFCLOCK_STATE_PAUSED */ CLOCK_NOTIFY_PAUSE,
3956 struct clock_state_change_param param;
3958 if (!clock->is_shut_down && clock->state != MFCLOCK_STATE_INVALID)
3960 param.u.offset = clock->start_offset;
3961 clock_notify_async_sink(clock, MFGetSystemTime(), param, notifications[clock->state], sink->state_sink);
3964 list_add_tail(&clock->sinks, &sink->entry);
3966 LeaveCriticalSection(&clock->cs);
3968 if (FAILED(hr))
3970 IMFClockStateSink_Release(sink->state_sink);
3971 heap_free(sink);
3974 return hr;
3977 static HRESULT WINAPI present_clock_RemoveClockStateSink(IMFPresentationClock *iface,
3978 IMFClockStateSink *state_sink)
3980 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3981 struct clock_sink *sink;
3983 TRACE("%p, %p.\n", iface, state_sink);
3985 if (!state_sink)
3986 return E_INVALIDARG;
3988 EnterCriticalSection(&clock->cs);
3989 LIST_FOR_EACH_ENTRY(sink, &clock->sinks, struct clock_sink, entry)
3991 if (sink->state_sink == state_sink)
3993 IMFClockStateSink_Release(sink->state_sink);
3994 list_remove(&sink->entry);
3995 heap_free(sink);
3996 break;
3999 LeaveCriticalSection(&clock->cs);
4001 return S_OK;
4004 static HRESULT clock_call_state_change(MFTIME system_time, struct clock_state_change_param param,
4005 enum clock_notification notification, IMFClockStateSink *sink)
4007 HRESULT hr = S_OK;
4009 switch (notification)
4011 case CLOCK_NOTIFY_START:
4012 hr = IMFClockStateSink_OnClockStart(sink, system_time, param.u.offset);
4013 break;
4014 case CLOCK_NOTIFY_STOP:
4015 hr = IMFClockStateSink_OnClockStop(sink, system_time);
4016 break;
4017 case CLOCK_NOTIFY_PAUSE:
4018 hr = IMFClockStateSink_OnClockPause(sink, system_time);
4019 break;
4020 case CLOCK_NOTIFY_RESTART:
4021 hr = IMFClockStateSink_OnClockRestart(sink, system_time);
4022 break;
4023 case CLOCK_NOTIFY_SET_RATE:
4024 /* System time source does not allow 0.0 rate, presentation clock allows it without raising errors. */
4025 IMFClockStateSink_OnClockSetRate(sink, system_time, param.u.rate);
4026 break;
4027 default:
4031 return hr;
4034 static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_command command,
4035 struct clock_state_change_param param)
4037 static const BYTE state_change_is_allowed[MFCLOCK_STATE_PAUSED+1][CLOCK_CMD_MAX] =
4038 { /* S S* P, R */
4039 /* INVALID */ { 1, 1, 1, 1 },
4040 /* RUNNING */ { 1, 1, 1, 1 },
4041 /* STOPPED */ { 1, 1, 0, 1 },
4042 /* PAUSED */ { 1, 1, 0, 1 },
4044 static const MFCLOCK_STATE states[CLOCK_CMD_MAX] =
4046 /* CLOCK_CMD_START */ MFCLOCK_STATE_RUNNING,
4047 /* CLOCK_CMD_STOP */ MFCLOCK_STATE_STOPPED,
4048 /* CLOCK_CMD_PAUSE */ MFCLOCK_STATE_PAUSED,
4049 /* CLOCK_CMD_SET_RATE */ 0, /* Unused */
4051 static const enum clock_notification notifications[CLOCK_CMD_MAX] =
4053 /* CLOCK_CMD_START */ CLOCK_NOTIFY_START,
4054 /* CLOCK_CMD_STOP */ CLOCK_NOTIFY_STOP,
4055 /* CLOCK_CMD_PAUSE */ CLOCK_NOTIFY_PAUSE,
4056 /* CLOCK_CMD_SET_RATE */ CLOCK_NOTIFY_SET_RATE,
4058 enum clock_notification notification;
4059 struct clock_sink *sink;
4060 MFCLOCK_STATE old_state;
4061 IMFAsyncResult *result;
4062 MFTIME system_time;
4063 HRESULT hr;
4065 if (!clock->time_source)
4066 return MF_E_CLOCK_NO_TIME_SOURCE;
4068 if (command != CLOCK_CMD_SET_RATE && clock->state == states[command] && clock->state != MFCLOCK_STATE_RUNNING)
4069 return MF_E_CLOCK_STATE_ALREADY_SET;
4071 if (!state_change_is_allowed[clock->state][command])
4072 return MF_E_INVALIDREQUEST;
4074 system_time = MFGetSystemTime();
4076 if (command == CLOCK_CMD_START && clock->state == MFCLOCK_STATE_PAUSED &&
4077 param.u.offset == PRESENTATION_CURRENT_POSITION)
4079 notification = CLOCK_NOTIFY_RESTART;
4081 else
4082 notification = notifications[command];
4084 if (FAILED(hr = clock_call_state_change(system_time, param, notification, clock->time_source_sink)))
4085 return hr;
4087 old_state = clock->state;
4088 if (command != CLOCK_CMD_SET_RATE)
4089 clock->state = states[command];
4091 /* Dump all pending timer requests immediately on start; otherwise try to cancel scheduled items when
4092 transitioning from running state. */
4093 if ((clock->state == MFCLOCK_STATE_RUNNING) ^ (old_state == MFCLOCK_STATE_RUNNING))
4095 struct clock_timer *timer, *timer2;
4097 if (clock->state == MFCLOCK_STATE_RUNNING)
4099 LIST_FOR_EACH_ENTRY_SAFE(timer, timer2, &clock->timers, struct clock_timer, entry)
4101 list_remove(&timer->entry);
4102 hr = MFCreateAsyncResult(&timer->IUnknown_iface, &clock->timer_callback, NULL, &result);
4103 IUnknown_Release(&timer->IUnknown_iface);
4104 if (SUCCEEDED(hr))
4106 MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_TIMER, result);
4107 IMFAsyncResult_Release(result);
4111 else
4113 LIST_FOR_EACH_ENTRY(timer, &clock->timers, struct clock_timer, entry)
4115 if (timer->key)
4117 MFCancelWorkItem(timer->key);
4118 timer->key = 0;
4124 LIST_FOR_EACH_ENTRY(sink, &clock->sinks, struct clock_sink, entry)
4126 clock_notify_async_sink(clock, system_time, param, notification, sink->state_sink);
4129 return S_OK;
4132 static HRESULT WINAPI present_clock_Start(IMFPresentationClock *iface, LONGLONG start_offset)
4134 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
4135 struct clock_state_change_param param = {{0}};
4136 HRESULT hr;
4138 TRACE("%p, %s.\n", iface, debugstr_time(start_offset));
4140 EnterCriticalSection(&clock->cs);
4141 clock->start_offset = param.u.offset = start_offset;
4142 hr = clock_change_state(clock, CLOCK_CMD_START, param);
4143 LeaveCriticalSection(&clock->cs);
4145 return hr;
4148 static HRESULT WINAPI present_clock_Stop(IMFPresentationClock *iface)
4150 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
4151 struct clock_state_change_param param = {{0}};
4152 HRESULT hr;
4154 TRACE("%p.\n", iface);
4156 EnterCriticalSection(&clock->cs);
4157 hr = clock_change_state(clock, CLOCK_CMD_STOP, param);
4158 LeaveCriticalSection(&clock->cs);
4160 return hr;
4163 static HRESULT WINAPI present_clock_Pause(IMFPresentationClock *iface)
4165 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
4166 struct clock_state_change_param param = {{0}};
4167 HRESULT hr;
4169 TRACE("%p.\n", iface);
4171 EnterCriticalSection(&clock->cs);
4172 hr = clock_change_state(clock, CLOCK_CMD_PAUSE, param);
4173 LeaveCriticalSection(&clock->cs);
4175 return hr;
4178 static const IMFPresentationClockVtbl presentationclockvtbl =
4180 present_clock_QueryInterface,
4181 present_clock_AddRef,
4182 present_clock_Release,
4183 present_clock_GetClockCharacteristics,
4184 present_clock_GetCorrelatedTime,
4185 present_clock_GetContinuityKey,
4186 present_clock_GetState,
4187 present_clock_GetProperties,
4188 present_clock_SetTimeSource,
4189 present_clock_GetTimeSource,
4190 present_clock_GetTime,
4191 present_clock_AddClockStateSink,
4192 present_clock_RemoveClockStateSink,
4193 present_clock_Start,
4194 present_clock_Stop,
4195 present_clock_Pause,
4198 static HRESULT WINAPI present_clock_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **out)
4200 struct presentation_clock *clock = impl_from_IMFRateControl(iface);
4201 return IMFPresentationClock_QueryInterface(&clock->IMFPresentationClock_iface, riid, out);
4204 static ULONG WINAPI present_clock_rate_control_AddRef(IMFRateControl *iface)
4206 struct presentation_clock *clock = impl_from_IMFRateControl(iface);
4207 return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
4210 static ULONG WINAPI present_clock_rate_control_Release(IMFRateControl *iface)
4212 struct presentation_clock *clock = impl_from_IMFRateControl(iface);
4213 return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
4216 static HRESULT WINAPI present_clock_rate_SetRate(IMFRateControl *iface, BOOL thin, float rate)
4218 struct presentation_clock *clock = impl_from_IMFRateControl(iface);
4219 struct clock_state_change_param param;
4220 HRESULT hr;
4222 TRACE("%p, %d, %f.\n", iface, thin, rate);
4224 if (thin)
4225 return MF_E_THINNING_UNSUPPORTED;
4227 EnterCriticalSection(&clock->cs);
4228 param.u.rate = rate;
4229 if (SUCCEEDED(hr = clock_change_state(clock, CLOCK_CMD_SET_RATE, param)))
4230 clock->rate = rate;
4231 LeaveCriticalSection(&clock->cs);
4233 return hr;
4236 static HRESULT WINAPI present_clock_rate_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
4238 struct presentation_clock *clock = impl_from_IMFRateControl(iface);
4240 TRACE("%p, %p, %p.\n", iface, thin, rate);
4242 if (!rate)
4243 return E_INVALIDARG;
4245 if (thin)
4246 *thin = FALSE;
4248 EnterCriticalSection(&clock->cs);
4249 *rate = clock->rate;
4250 LeaveCriticalSection(&clock->cs);
4252 return S_OK;
4255 static const IMFRateControlVtbl presentclockratecontrolvtbl =
4257 present_clock_rate_control_QueryInterface,
4258 present_clock_rate_control_AddRef,
4259 present_clock_rate_control_Release,
4260 present_clock_rate_SetRate,
4261 present_clock_rate_GetRate,
4264 static HRESULT WINAPI present_clock_timer_QueryInterface(IMFTimer *iface, REFIID riid, void **out)
4266 struct presentation_clock *clock = impl_from_IMFTimer(iface);
4267 return IMFPresentationClock_QueryInterface(&clock->IMFPresentationClock_iface, riid, out);
4270 static ULONG WINAPI present_clock_timer_AddRef(IMFTimer *iface)
4272 struct presentation_clock *clock = impl_from_IMFTimer(iface);
4273 return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
4276 static ULONG WINAPI present_clock_timer_Release(IMFTimer *iface)
4278 struct presentation_clock *clock = impl_from_IMFTimer(iface);
4279 return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
4282 static HRESULT present_clock_schedule_timer(struct presentation_clock *clock, DWORD flags, LONGLONG time,
4283 struct clock_timer *timer)
4285 IMFAsyncResult *result;
4286 MFTIME systime, clocktime;
4287 LONGLONG frequency;
4288 HRESULT hr;
4290 if (!(flags & MFTIMER_RELATIVE))
4292 if (FAILED(hr = IMFPresentationTimeSource_GetCorrelatedTime(clock->time_source, 0, &clocktime, &systime)))
4294 WARN("Failed to get clock time, hr %#x.\n", hr);
4295 return hr;
4297 time -= clocktime;
4300 frequency = clock->frequency / 1000;
4301 time /= frequency;
4303 /* Scheduled item is using clock instance callback, with timer instance as an object. Clock callback will
4304 call user callback and cleanup timer list. */
4306 if (FAILED(hr = MFCreateAsyncResult(&timer->IUnknown_iface, &clock->timer_callback, NULL, &result)))
4307 return hr;
4309 hr = MFScheduleWorkItemEx(result, -time, &timer->key);
4310 IMFAsyncResult_Release(result);
4312 return hr;
4315 static HRESULT WINAPI clock_timer_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
4317 if (IsEqualIID(riid, &IID_IUnknown))
4319 *obj = iface;
4320 IUnknown_AddRef(iface);
4321 return S_OK;
4324 *obj = NULL;
4325 return E_NOINTERFACE;
4328 static ULONG WINAPI clock_timer_AddRef(IUnknown *iface)
4330 struct clock_timer *timer = impl_clock_timer_from_IUnknown(iface);
4331 return InterlockedIncrement(&timer->refcount);
4334 static ULONG WINAPI clock_timer_Release(IUnknown *iface)
4336 struct clock_timer *timer = impl_clock_timer_from_IUnknown(iface);
4337 ULONG refcount = InterlockedDecrement(&timer->refcount);
4339 if (!refcount)
4341 IMFAsyncResult_Release(timer->result);
4342 IMFAsyncCallback_Release(timer->callback);
4343 heap_free(timer);
4346 return refcount;
4349 static const IUnknownVtbl clock_timer_vtbl =
4351 clock_timer_QueryInterface,
4352 clock_timer_AddRef,
4353 clock_timer_Release,
4356 static HRESULT WINAPI present_clock_timer_SetTimer(IMFTimer *iface, DWORD flags, LONGLONG time,
4357 IMFAsyncCallback *callback, IUnknown *state, IUnknown **cancel_key)
4359 struct presentation_clock *clock = impl_from_IMFTimer(iface);
4360 struct clock_timer *clock_timer;
4361 HRESULT hr;
4363 TRACE("%p, %#x, %s, %p, %p, %p.\n", iface, flags, debugstr_time(time), callback, state, cancel_key);
4365 if (!(clock_timer = heap_alloc_zero(sizeof(*clock_timer))))
4366 return E_OUTOFMEMORY;
4368 if (FAILED(hr = MFCreateAsyncResult(NULL, NULL, state, &clock_timer->result)))
4370 heap_free(clock_timer);
4371 return hr;
4374 clock_timer->IUnknown_iface.lpVtbl = &clock_timer_vtbl;
4375 clock_timer->refcount = 1;
4376 clock_timer->callback = callback;
4377 IMFAsyncCallback_AddRef(clock_timer->callback);
4379 EnterCriticalSection(&clock->cs);
4381 if (clock->state == MFCLOCK_STATE_RUNNING)
4382 hr = present_clock_schedule_timer(clock, flags, time, clock_timer);
4383 else if (clock->state == MFCLOCK_STATE_STOPPED)
4384 hr = MF_S_CLOCK_STOPPED;
4386 if (SUCCEEDED(hr))
4388 list_add_tail(&clock->timers, &clock_timer->entry);
4389 if (cancel_key)
4391 *cancel_key = &clock_timer->IUnknown_iface;
4392 IUnknown_AddRef(*cancel_key);
4396 LeaveCriticalSection(&clock->cs);
4398 if (FAILED(hr))
4399 IUnknown_Release(&clock_timer->IUnknown_iface);
4401 return hr;
4404 static HRESULT WINAPI present_clock_timer_CancelTimer(IMFTimer *iface, IUnknown *cancel_key)
4406 struct presentation_clock *clock = impl_from_IMFTimer(iface);
4407 struct clock_timer *timer;
4409 TRACE("%p, %p.\n", iface, cancel_key);
4411 EnterCriticalSection(&clock->cs);
4413 LIST_FOR_EACH_ENTRY(timer, &clock->timers, struct clock_timer, entry)
4415 if (&timer->IUnknown_iface == cancel_key)
4417 list_remove(&timer->entry);
4418 if (timer->key)
4420 MFCancelWorkItem(timer->key);
4421 timer->key = 0;
4423 IUnknown_Release(&timer->IUnknown_iface);
4424 break;
4428 LeaveCriticalSection(&clock->cs);
4430 return S_OK;
4433 static const IMFTimerVtbl presentclocktimervtbl =
4435 present_clock_timer_QueryInterface,
4436 present_clock_timer_AddRef,
4437 present_clock_timer_Release,
4438 present_clock_timer_SetTimer,
4439 present_clock_timer_CancelTimer,
4442 static HRESULT WINAPI present_clock_shutdown_QueryInterface(IMFShutdown *iface, REFIID riid, void **out)
4444 struct presentation_clock *clock = impl_from_IMFShutdown(iface);
4445 return IMFPresentationClock_QueryInterface(&clock->IMFPresentationClock_iface, riid, out);
4448 static ULONG WINAPI present_clock_shutdown_AddRef(IMFShutdown *iface)
4450 struct presentation_clock *clock = impl_from_IMFShutdown(iface);
4451 return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
4454 static ULONG WINAPI present_clock_shutdown_Release(IMFShutdown *iface)
4456 struct presentation_clock *clock = impl_from_IMFShutdown(iface);
4457 return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
4460 static HRESULT WINAPI present_clock_shutdown_Shutdown(IMFShutdown *iface)
4462 struct presentation_clock *clock = impl_from_IMFShutdown(iface);
4464 TRACE("%p.\n", iface);
4466 EnterCriticalSection(&clock->cs);
4467 clock->is_shut_down = TRUE;
4468 LeaveCriticalSection(&clock->cs);
4470 return S_OK;
4473 static HRESULT WINAPI present_clock_shutdown_GetShutdownStatus(IMFShutdown *iface, MFSHUTDOWN_STATUS *status)
4475 struct presentation_clock *clock = impl_from_IMFShutdown(iface);
4476 HRESULT hr = S_OK;
4478 TRACE("%p, %p.\n", iface, status);
4480 if (!status)
4481 return E_INVALIDARG;
4483 EnterCriticalSection(&clock->cs);
4484 if (clock->is_shut_down)
4485 *status = MFSHUTDOWN_COMPLETED;
4486 else
4487 hr = MF_E_INVALIDREQUEST;
4488 LeaveCriticalSection(&clock->cs);
4490 return hr;
4493 static const IMFShutdownVtbl presentclockshutdownvtbl =
4495 present_clock_shutdown_QueryInterface,
4496 present_clock_shutdown_AddRef,
4497 present_clock_shutdown_Release,
4498 present_clock_shutdown_Shutdown,
4499 present_clock_shutdown_GetShutdownStatus,
4502 static HRESULT WINAPI present_clock_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **out)
4504 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
4505 IsEqualIID(riid, &IID_IUnknown))
4507 *out = iface;
4508 IMFAsyncCallback_AddRef(iface);
4509 return S_OK;
4512 WARN("Unsupported %s.\n", wine_dbgstr_guid(riid));
4513 *out = NULL;
4514 return E_NOINTERFACE;
4517 static ULONG WINAPI present_clock_sink_callback_AddRef(IMFAsyncCallback *iface)
4519 struct presentation_clock *clock = impl_from_sink_callback_IMFAsyncCallback(iface);
4520 return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
4523 static ULONG WINAPI present_clock_sink_callback_Release(IMFAsyncCallback *iface)
4525 struct presentation_clock *clock = impl_from_sink_callback_IMFAsyncCallback(iface);
4526 return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
4529 static HRESULT WINAPI present_clock_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
4531 return E_NOTIMPL;
4534 static HRESULT WINAPI present_clock_sink_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
4536 struct sink_notification *data;
4537 IUnknown *object;
4538 HRESULT hr;
4540 if (FAILED(hr = IMFAsyncResult_GetObject(result, &object)))
4541 return hr;
4543 data = impl_sink_notification_from_IUnknown(object);
4545 clock_call_state_change(data->system_time, data->param, data->notification, data->sink);
4547 IUnknown_Release(object);
4549 return S_OK;
4552 static const IMFAsyncCallbackVtbl presentclocksinkcallbackvtbl =
4554 present_clock_callback_QueryInterface,
4555 present_clock_sink_callback_AddRef,
4556 present_clock_sink_callback_Release,
4557 present_clock_callback_GetParameters,
4558 present_clock_sink_callback_Invoke,
4561 static ULONG WINAPI present_clock_timer_callback_AddRef(IMFAsyncCallback *iface)
4563 struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface);
4564 return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
4567 static ULONG WINAPI present_clock_timer_callback_Release(IMFAsyncCallback *iface)
4569 struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface);
4570 return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
4573 static HRESULT WINAPI present_clock_timer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
4575 struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface);
4576 struct clock_timer *timer;
4577 IUnknown *object;
4578 HRESULT hr;
4580 if (FAILED(hr = IMFAsyncResult_GetObject(result, &object)))
4581 return hr;
4583 timer = impl_clock_timer_from_IUnknown(object);
4585 EnterCriticalSection(&clock->cs);
4586 list_remove(&timer->entry);
4587 IUnknown_Release(&timer->IUnknown_iface);
4588 LeaveCriticalSection(&clock->cs);
4590 IMFAsyncCallback_Invoke(timer->callback, timer->result);
4592 IUnknown_Release(object);
4594 return S_OK;
4597 static const IMFAsyncCallbackVtbl presentclocktimercallbackvtbl =
4599 present_clock_callback_QueryInterface,
4600 present_clock_timer_callback_AddRef,
4601 present_clock_timer_callback_Release,
4602 present_clock_callback_GetParameters,
4603 present_clock_timer_callback_Invoke,
4606 /***********************************************************************
4607 * MFCreatePresentationClock (mf.@)
4609 HRESULT WINAPI MFCreatePresentationClock(IMFPresentationClock **clock)
4611 struct presentation_clock *object;
4613 TRACE("%p.\n", clock);
4615 object = heap_alloc_zero(sizeof(*object));
4616 if (!object)
4617 return E_OUTOFMEMORY;
4619 object->IMFPresentationClock_iface.lpVtbl = &presentationclockvtbl;
4620 object->IMFRateControl_iface.lpVtbl = &presentclockratecontrolvtbl;
4621 object->IMFTimer_iface.lpVtbl = &presentclocktimervtbl;
4622 object->IMFShutdown_iface.lpVtbl = &presentclockshutdownvtbl;
4623 object->sink_callback.lpVtbl = &presentclocksinkcallbackvtbl;
4624 object->timer_callback.lpVtbl = &presentclocktimercallbackvtbl;
4625 object->refcount = 1;
4626 list_init(&object->sinks);
4627 list_init(&object->timers);
4628 object->rate = 1.0f;
4629 InitializeCriticalSection(&object->cs);
4631 *clock = &object->IMFPresentationClock_iface;
4633 return S_OK;
4636 static HRESULT WINAPI standard_quality_manager_QueryInterface(IMFQualityManager *iface, REFIID riid, void **out)
4638 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
4640 if (IsEqualIID(riid, &IID_IMFQualityManager) ||
4641 IsEqualIID(riid, &IID_IUnknown))
4643 *out = iface;
4644 IMFQualityManager_AddRef(iface);
4645 return S_OK;
4648 WARN("Unsupported %s.\n", debugstr_guid(riid));
4649 *out = NULL;
4650 return E_NOINTERFACE;
4653 static ULONG WINAPI standard_quality_manager_AddRef(IMFQualityManager *iface)
4655 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
4656 ULONG refcount = InterlockedIncrement(&manager->refcount);
4658 TRACE("%p, refcount %u.\n", iface, refcount);
4660 return refcount;
4663 static ULONG WINAPI standard_quality_manager_Release(IMFQualityManager *iface)
4665 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
4666 ULONG refcount = InterlockedDecrement(&manager->refcount);
4668 TRACE("%p, refcount %u.\n", iface, refcount);
4670 if (!refcount)
4672 if (manager->clock)
4673 IMFPresentationClock_Release(manager->clock);
4674 DeleteCriticalSection(&manager->cs);
4675 heap_free(manager);
4678 return refcount;
4681 static HRESULT WINAPI standard_quality_manager_NotifyTopology(IMFQualityManager *iface, IMFTopology *topology)
4683 FIXME("%p, %p stub.\n", iface, topology);
4685 return S_OK;
4688 static HRESULT WINAPI standard_quality_manager_NotifyPresentationClock(IMFQualityManager *iface,
4689 IMFPresentationClock *clock)
4691 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
4693 TRACE("%p, %p.\n", iface, clock);
4695 if (!clock)
4696 return E_POINTER;
4698 EnterCriticalSection(&manager->cs);
4699 if (manager->clock)
4700 IMFPresentationClock_Release(manager->clock);
4701 manager->clock = clock;
4702 IMFPresentationClock_AddRef(manager->clock);
4703 LeaveCriticalSection(&manager->cs);
4705 return S_OK;
4708 static HRESULT WINAPI standard_quality_manager_NotifyProcessInput(IMFQualityManager *iface, IMFTopologyNode *node,
4709 LONG input_index, IMFSample *sample)
4711 TRACE("%p, %p, %d, %p stub.\n", iface, node, input_index, sample);
4713 return E_NOTIMPL;
4716 static HRESULT WINAPI standard_quality_manager_NotifyProcessOutput(IMFQualityManager *iface, IMFTopologyNode *node,
4717 LONG output_index, IMFSample *sample)
4719 TRACE("%p, %p, %d, %p stub.\n", iface, node, output_index, sample);
4721 return E_NOTIMPL;
4724 static HRESULT WINAPI standard_quality_manager_NotifyQualityEvent(IMFQualityManager *iface, IUnknown *object,
4725 IMFMediaEvent *event)
4727 FIXME("%p, %p, %p stub.\n", iface, object, event);
4729 return E_NOTIMPL;
4732 static HRESULT WINAPI standard_quality_manager_Shutdown(IMFQualityManager *iface)
4734 FIXME("%p stub.\n", iface);
4736 return E_NOTIMPL;
4739 static IMFQualityManagerVtbl standard_quality_manager_vtbl =
4741 standard_quality_manager_QueryInterface,
4742 standard_quality_manager_AddRef,
4743 standard_quality_manager_Release,
4744 standard_quality_manager_NotifyTopology,
4745 standard_quality_manager_NotifyPresentationClock,
4746 standard_quality_manager_NotifyProcessInput,
4747 standard_quality_manager_NotifyProcessOutput,
4748 standard_quality_manager_NotifyQualityEvent,
4749 standard_quality_manager_Shutdown,
4752 HRESULT WINAPI MFCreateStandardQualityManager(IMFQualityManager **manager)
4754 struct quality_manager *object;
4756 TRACE("%p.\n", manager);
4758 object = heap_alloc_zero(sizeof(*object));
4759 if (!object)
4760 return E_OUTOFMEMORY;
4762 object->IMFQualityManager_iface.lpVtbl = &standard_quality_manager_vtbl;
4763 object->refcount = 1;
4764 InitializeCriticalSection(&object->cs);
4766 *manager = &object->IMFQualityManager_iface;
4768 return S_OK;