mf/session: Keep a reference to the original activation object when binding sink...
[wine.git] / dlls / mf / session.c
blob0381917826a59ef3e7352604e6138fc0fd8439aa
1 /*
2 * Copyright 2017 Nikolay Sivov
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
20 #include <math.h>
22 #define COBJMACROS
24 #include "windef.h"
25 #include "winbase.h"
26 #include "mfidl.h"
27 #include "evr.h"
29 #include "wine/debug.h"
30 #include "wine/heap.h"
31 #include "wine/list.h"
33 #include "mf_private.h"
35 #include "initguid.h"
37 DEFINE_GUID(_MF_TOPONODE_IMFActivate, 0x33706f4a, 0x309a, 0x49be, 0xa8, 0xdd, 0xe7, 0xc0, 0x87, 0x5e, 0xb6, 0x79);
39 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
41 enum session_command
43 SESSION_CMD_CLEAR_TOPOLOGIES,
44 SESSION_CMD_CLOSE,
45 SESSION_CMD_SET_TOPOLOGY,
46 SESSION_CMD_START,
47 SESSION_CMD_PAUSE,
48 SESSION_CMD_STOP,
49 /* Internally used commands. */
50 SESSION_CMD_END,
51 SESSION_CMD_QM_NOTIFY_TOPOLOGY,
52 SESSION_CMD_SA_READY,
55 struct session_op
57 IUnknown IUnknown_iface;
58 LONG refcount;
59 enum session_command command;
60 union
62 struct
64 DWORD flags;
65 IMFTopology *topology;
66 } set_topology;
67 struct
69 GUID time_format;
70 PROPVARIANT start_position;
71 } start;
72 struct
74 IMFTopology *topology;
75 } notify_topology;
76 struct
78 TOPOID node_id;
79 } sa_ready;
80 } u;
81 struct list entry;
84 struct queued_topology
86 struct list entry;
87 IMFTopology *topology;
88 MF_TOPOSTATUS status;
91 enum session_state
93 SESSION_STATE_STOPPED = 0,
94 SESSION_STATE_STARTING_SOURCES,
95 SESSION_STATE_PREROLLING_SINKS,
96 SESSION_STATE_STARTING_SINKS,
97 SESSION_STATE_STARTED,
98 SESSION_STATE_PAUSING_SINKS,
99 SESSION_STATE_PAUSING_SOURCES,
100 SESSION_STATE_PAUSED,
101 SESSION_STATE_STOPPING_SINKS,
102 SESSION_STATE_STOPPING_SOURCES,
103 SESSION_STATE_FINALIZING_SINKS,
104 SESSION_STATE_CLOSED,
105 SESSION_STATE_SHUT_DOWN,
108 enum object_state
110 OBJ_STATE_STOPPED = 0,
111 OBJ_STATE_STARTED,
112 OBJ_STATE_PAUSED,
113 OBJ_STATE_PREROLLED,
114 OBJ_STATE_INVALID,
117 enum media_source_flags
119 SOURCE_FLAG_END_OF_PRESENTATION = 0x1,
122 struct media_source
124 struct list entry;
125 IMFMediaSource *source;
126 IMFPresentationDescriptor *pd;
127 enum object_state state;
128 unsigned int flags;
131 struct media_sink
133 struct list entry;
134 IMFMediaSink *sink;
135 IMFMediaSinkPreroll *preroll;
136 IMFMediaEventGenerator *event_generator;
137 BOOL finalized;
140 struct sample
142 struct list entry;
143 IMFSample *sample;
146 struct transform_stream
148 struct list samples;
149 unsigned int requests;
152 enum topo_node_flags
154 TOPO_NODE_END_OF_STREAM = 0x1,
157 struct topo_node
159 struct list entry;
160 struct media_session *session;
161 MF_TOPOLOGY_TYPE type;
162 TOPOID node_id;
163 IMFTopologyNode *node;
164 enum object_state state;
165 unsigned int flags;
166 union
168 IMFMediaStream *source_stream;
169 IMFStreamSink *sink_stream;
170 IMFTransform *transform;
171 IUnknown *object;
172 } object;
174 union
176 struct
178 IMFMediaSource *source;
179 unsigned int stream_id;
180 } source;
181 struct
183 unsigned int requests;
184 IMFVideoSampleAllocatorNotify notify_cb;
185 IMFVideoSampleAllocator *allocator;
186 IMFVideoSampleAllocatorCallback *allocator_cb;
187 } sink;
188 struct
190 struct transform_stream *inputs;
191 unsigned int *input_map;
192 unsigned int input_count;
194 struct transform_stream *outputs;
195 unsigned int *output_map;
196 unsigned int output_count;
197 } transform;
198 } u;
201 enum presentation_flags
203 SESSION_FLAG_SOURCES_SUBSCRIBED = 0x1,
204 SESSION_FLAG_PRESENTATION_CLOCK_SET = 0x2,
205 SESSION_FLAG_FINALIZE_SINKS = 0x4,
206 SESSION_FLAG_NEEDS_PREROLL = 0x8,
207 SESSION_FLAG_END_OF_PRESENTATION = 0x10,
210 struct media_session
212 IMFMediaSession IMFMediaSession_iface;
213 IMFGetService IMFGetService_iface;
214 IMFRateSupport IMFRateSupport_iface;
215 IMFRateControl IMFRateControl_iface;
216 IMFAsyncCallback commands_callback;
217 IMFAsyncCallback events_callback;
218 IMFAsyncCallback sink_finalizer_callback;
219 LONG refcount;
220 IMFMediaEventQueue *event_queue;
221 IMFPresentationClock *clock;
222 IMFPresentationTimeSource *system_time_source;
223 IMFRateControl *clock_rate_control;
224 IMFTopoLoader *topo_loader;
225 IMFQualityManager *quality_manager;
226 struct
228 IMFTopology *current_topology;
229 MF_TOPOSTATUS topo_status;
230 MFTIME clock_stop_time;
231 unsigned int flags;
232 struct list sources;
233 struct list sinks;
234 struct list nodes;
236 /* Latest Start() arguments. */
237 GUID time_format;
238 PROPVARIANT start_position;
239 } presentation;
240 struct list topologies;
241 struct list commands;
242 enum session_state state;
243 DWORD caps;
244 CRITICAL_SECTION cs;
247 struct clock_sink
249 struct list entry;
250 IMFClockStateSink *state_sink;
253 enum clock_command
255 CLOCK_CMD_START = 0,
256 CLOCK_CMD_STOP,
257 CLOCK_CMD_PAUSE,
258 CLOCK_CMD_SET_RATE,
259 CLOCK_CMD_MAX,
262 enum clock_notification
264 CLOCK_NOTIFY_START,
265 CLOCK_NOTIFY_STOP,
266 CLOCK_NOTIFY_PAUSE,
267 CLOCK_NOTIFY_RESTART,
268 CLOCK_NOTIFY_SET_RATE,
271 struct clock_state_change_param
273 union
275 LONGLONG offset;
276 float rate;
277 } u;
280 struct sink_notification
282 IUnknown IUnknown_iface;
283 LONG refcount;
284 MFTIME system_time;
285 struct clock_state_change_param param;
286 enum clock_notification notification;
287 IMFClockStateSink *sink;
290 struct clock_timer
292 IUnknown IUnknown_iface;
293 LONG refcount;
294 IMFAsyncResult *result;
295 IMFAsyncCallback *callback;
296 MFWORKITEM_KEY key;
297 struct list entry;
300 struct presentation_clock
302 IMFPresentationClock IMFPresentationClock_iface;
303 IMFRateControl IMFRateControl_iface;
304 IMFTimer IMFTimer_iface;
305 IMFShutdown IMFShutdown_iface;
306 IMFAsyncCallback sink_callback;
307 IMFAsyncCallback timer_callback;
308 LONG refcount;
309 IMFPresentationTimeSource *time_source;
310 IMFClockStateSink *time_source_sink;
311 MFCLOCK_STATE state;
312 LONGLONG start_offset;
313 struct list sinks;
314 struct list timers;
315 float rate;
316 LONGLONG frequency;
317 CRITICAL_SECTION cs;
318 BOOL is_shut_down;
321 struct quality_manager
323 IMFQualityManager IMFQualityManager_iface;
324 LONG refcount;
326 IMFPresentationClock *clock;
327 CRITICAL_SECTION cs;
330 static inline struct media_session *impl_from_IMFMediaSession(IMFMediaSession *iface)
332 return CONTAINING_RECORD(iface, struct media_session, IMFMediaSession_iface);
335 static struct media_session *impl_from_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
337 return CONTAINING_RECORD(iface, struct media_session, commands_callback);
340 static struct media_session *impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
342 return CONTAINING_RECORD(iface, struct media_session, events_callback);
345 static struct media_session *impl_from_sink_finalizer_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
347 return CONTAINING_RECORD(iface, struct media_session, sink_finalizer_callback);
350 static struct media_session *impl_from_IMFGetService(IMFGetService *iface)
352 return CONTAINING_RECORD(iface, struct media_session, IMFGetService_iface);
355 static struct media_session *impl_session_from_IMFRateSupport(IMFRateSupport *iface)
357 return CONTAINING_RECORD(iface, struct media_session, IMFRateSupport_iface);
360 static struct media_session *impl_session_from_IMFRateControl(IMFRateControl *iface)
362 return CONTAINING_RECORD(iface, struct media_session, IMFRateControl_iface);
365 static struct session_op *impl_op_from_IUnknown(IUnknown *iface)
367 return CONTAINING_RECORD(iface, struct session_op, IUnknown_iface);
370 static struct presentation_clock *impl_from_IMFPresentationClock(IMFPresentationClock *iface)
372 return CONTAINING_RECORD(iface, struct presentation_clock, IMFPresentationClock_iface);
375 static struct presentation_clock *impl_from_IMFRateControl(IMFRateControl *iface)
377 return CONTAINING_RECORD(iface, struct presentation_clock, IMFRateControl_iface);
380 static struct presentation_clock *impl_from_IMFTimer(IMFTimer *iface)
382 return CONTAINING_RECORD(iface, struct presentation_clock, IMFTimer_iface);
385 static struct presentation_clock *impl_from_IMFShutdown(IMFShutdown *iface)
387 return CONTAINING_RECORD(iface, struct presentation_clock, IMFShutdown_iface);
390 static struct presentation_clock *impl_from_sink_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
392 return CONTAINING_RECORD(iface, struct presentation_clock, sink_callback);
395 static struct presentation_clock *impl_from_timer_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
397 return CONTAINING_RECORD(iface, struct presentation_clock, timer_callback);
400 static struct clock_timer *impl_clock_timer_from_IUnknown(IUnknown *iface)
402 return CONTAINING_RECORD(iface, struct clock_timer, IUnknown_iface);
405 static struct sink_notification *impl_sink_notification_from_IUnknown(IUnknown *iface)
407 return CONTAINING_RECORD(iface, struct sink_notification, IUnknown_iface);
410 static struct quality_manager *impl_from_IMFQualityManager(IMFQualityManager *iface)
412 return CONTAINING_RECORD(iface, struct quality_manager, IMFQualityManager_iface);
415 static struct topo_node *impl_node_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify *iface)
417 return CONTAINING_RECORD(iface, struct topo_node, u.sink.notify_cb);
420 /* IMFLocalMFTRegistration */
421 static HRESULT WINAPI local_mft_registration_QueryInterface(IMFLocalMFTRegistration *iface, REFIID riid, void **obj)
423 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
425 if (IsEqualIID(riid, &IID_IMFLocalMFTRegistration) ||
426 IsEqualIID(riid, &IID_IUnknown))
428 *obj = iface;
429 IMFLocalMFTRegistration_AddRef(iface);
430 return S_OK;
433 WARN("Unexpected %s.\n", debugstr_guid(riid));
434 *obj = NULL;
435 return E_NOINTERFACE;
438 static ULONG WINAPI local_mft_registration_AddRef(IMFLocalMFTRegistration *iface)
440 return 2;
443 static ULONG WINAPI local_mft_registration_Release(IMFLocalMFTRegistration *iface)
445 return 1;
448 static HRESULT WINAPI local_mft_registration_RegisterMFTs(IMFLocalMFTRegistration *iface, MFT_REGISTRATION_INFO *info,
449 DWORD count)
451 HRESULT hr = S_OK;
452 DWORD i;
454 TRACE("%p, %p, %u.\n", iface, info, count);
456 for (i = 0; i < count; ++i)
458 if (FAILED(hr = MFTRegisterLocalByCLSID(&info[i].clsid, &info[i].guidCategory, info[i].pszName,
459 info[i].uiFlags, info[i].cInTypes, info[i].pInTypes, info[i].cOutTypes, info[i].pOutTypes)))
461 break;
465 return hr;
468 static const IMFLocalMFTRegistrationVtbl local_mft_registration_vtbl =
470 local_mft_registration_QueryInterface,
471 local_mft_registration_AddRef,
472 local_mft_registration_Release,
473 local_mft_registration_RegisterMFTs,
476 static IMFLocalMFTRegistration local_mft_registration = { &local_mft_registration_vtbl };
478 static HRESULT WINAPI session_op_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
480 if (IsEqualIID(riid, &IID_IUnknown))
482 *obj = iface;
483 IUnknown_AddRef(iface);
484 return S_OK;
487 *obj = NULL;
488 return E_NOINTERFACE;
491 static ULONG WINAPI session_op_AddRef(IUnknown *iface)
493 struct session_op *op = impl_op_from_IUnknown(iface);
494 ULONG refcount = InterlockedIncrement(&op->refcount);
496 TRACE("%p, refcount %u.\n", iface, refcount);
498 return refcount;
501 static ULONG WINAPI session_op_Release(IUnknown *iface)
503 struct session_op *op = impl_op_from_IUnknown(iface);
504 ULONG refcount = InterlockedDecrement(&op->refcount);
506 TRACE("%p, refcount %u.\n", iface, refcount);
508 if (!refcount)
510 switch (op->command)
512 case SESSION_CMD_SET_TOPOLOGY:
513 if (op->u.set_topology.topology)
514 IMFTopology_Release(op->u.set_topology.topology);
515 break;
516 case SESSION_CMD_START:
517 PropVariantClear(&op->u.start.start_position);
518 break;
519 case SESSION_CMD_QM_NOTIFY_TOPOLOGY:
520 if (op->u.notify_topology.topology)
521 IMFTopology_Release(op->u.notify_topology.topology);
522 break;
523 default:
526 heap_free(op);
529 return refcount;
532 static IUnknownVtbl session_op_vtbl =
534 session_op_QueryInterface,
535 session_op_AddRef,
536 session_op_Release,
539 static HRESULT create_session_op(enum session_command command, struct session_op **ret)
541 struct session_op *op;
543 if (!(op = heap_alloc_zero(sizeof(*op))))
544 return E_OUTOFMEMORY;
546 op->IUnknown_iface.lpVtbl = &session_op_vtbl;
547 op->refcount = 1;
548 op->command = command;
550 *ret = op;
552 return S_OK;
555 static HRESULT session_is_shut_down(struct media_session *session)
557 return session->state == SESSION_STATE_SHUT_DOWN ? MF_E_SHUTDOWN : S_OK;
560 static void session_push_back_command(struct media_session *session, enum session_command command)
562 struct session_op *op;
564 if (SUCCEEDED(create_session_op(command, &op)))
565 list_add_head(&session->commands, &op->entry);
568 static HRESULT session_submit_command(struct media_session *session, struct session_op *op)
570 HRESULT hr;
572 EnterCriticalSection(&session->cs);
573 if (SUCCEEDED(hr = session_is_shut_down(session)))
575 if (list_empty(&session->commands))
576 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface);
577 list_add_tail(&session->commands, &op->entry);
578 IUnknown_AddRef(&op->IUnknown_iface);
580 LeaveCriticalSection(&session->cs);
582 return hr;
585 static HRESULT session_submit_simple_command(struct media_session *session, enum session_command command)
587 struct session_op *op;
588 HRESULT hr;
590 if (FAILED(hr = create_session_op(command, &op)))
591 return hr;
593 hr = session_submit_command(session, op);
594 IUnknown_Release(&op->IUnknown_iface);
595 return hr;
598 static void session_clear_topologies(struct media_session *session)
600 struct queued_topology *ptr, *next;
602 LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &session->topologies, struct queued_topology, entry)
604 list_remove(&ptr->entry);
605 IMFTopology_Release(ptr->topology);
606 heap_free(ptr);
610 static void session_set_topo_status(struct media_session *session, HRESULT status,
611 MF_TOPOSTATUS topo_status)
613 IMFMediaEvent *event;
614 PROPVARIANT param;
616 if (topo_status == MF_TOPOSTATUS_INVALID)
617 return;
619 if (list_empty(&session->topologies))
621 FIXME("Unexpectedly empty topology queue.\n");
622 return;
625 if (topo_status > session->presentation.topo_status)
627 struct queued_topology *topology = LIST_ENTRY(list_head(&session->topologies), struct queued_topology, entry);
629 param.vt = VT_UNKNOWN;
630 param.punkVal = (IUnknown *)topology->topology;
632 if (FAILED(MFCreateMediaEvent(MESessionTopologyStatus, &GUID_NULL, status, &param, &event)))
633 return;
635 session->presentation.topo_status = topo_status;
637 IMFMediaEvent_SetUINT32(event, &MF_EVENT_TOPOLOGY_STATUS, topo_status);
638 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
639 IMFMediaEvent_Release(event);
643 static HRESULT session_bind_output_nodes(IMFTopology *topology)
645 MF_TOPOLOGY_TYPE node_type;
646 IMFStreamSink *stream_sink;
647 IMFMediaSink *media_sink;
648 WORD node_count = 0, i;
649 IMFTopologyNode *node;
650 IMFActivate *activate;
651 UINT32 stream_id;
652 IUnknown *object;
653 HRESULT hr;
655 hr = IMFTopology_GetNodeCount(topology, &node_count);
657 for (i = 0; i < node_count; ++i)
659 if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
660 break;
662 if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type)) || node_type != MF_TOPOLOGY_OUTPUT_NODE)
664 IMFTopologyNode_Release(node);
665 continue;
668 if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object)))
670 stream_sink = NULL;
671 if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&stream_sink)))
673 if (SUCCEEDED(hr = IUnknown_QueryInterface(object, &IID_IMFActivate, (void **)&activate)))
675 if (SUCCEEDED(hr = IMFActivate_ActivateObject(activate, &IID_IMFMediaSink, (void **)&media_sink)))
677 if (FAILED(IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_STREAMID, &stream_id)))
678 stream_id = 0;
680 stream_sink = NULL;
681 if (FAILED(IMFMediaSink_GetStreamSinkById(media_sink, stream_id, &stream_sink)))
682 hr = IMFMediaSink_AddStreamSink(media_sink, stream_id, NULL, &stream_sink);
684 if (stream_sink)
685 hr = IMFTopologyNode_SetObject(node, (IUnknown *)stream_sink);
687 IMFMediaSink_Release(media_sink);
690 if (SUCCEEDED(hr))
691 IMFTopologyNode_SetUnknown(node, &_MF_TOPONODE_IMFActivate, (IUnknown *)activate);
693 IMFActivate_Release(activate);
697 if (stream_sink)
698 IMFStreamSink_Release(stream_sink);
699 IUnknown_Release(object);
702 IMFTopologyNode_Release(node);
705 return hr;
708 static void session_set_caps(struct media_session *session, DWORD caps)
710 DWORD delta = session->caps ^ caps;
711 IMFMediaEvent *event;
713 /* Delta is documented to reflect rate value changes as well, but it's not clear what to compare
714 them to, since session always queries for current object rates. */
715 if (!delta)
716 return;
718 session->caps = caps;
720 if (FAILED(MFCreateMediaEvent(MESessionCapabilitiesChanged, &GUID_NULL, S_OK, NULL, &event)))
721 return;
723 IMFMediaEvent_SetUINT32(event, &MF_EVENT_SESSIONCAPS, caps);
724 IMFMediaEvent_SetUINT32(event, &MF_EVENT_SESSIONCAPS_DELTA, delta);
726 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
727 IMFMediaEvent_Release(event);
730 static void transform_release_sample(struct sample *sample)
732 list_remove(&sample->entry);
733 if (sample->sample)
734 IMFSample_Release(sample->sample);
735 heap_free(sample);
738 static void transform_stream_drop_samples(struct transform_stream *stream)
740 struct sample *sample, *sample2;
742 LIST_FOR_EACH_ENTRY_SAFE(sample, sample2, &stream->samples, struct sample, entry)
743 transform_release_sample(sample);
746 static void release_topo_node(struct topo_node *node)
748 unsigned int i;
750 switch (node->type)
752 case MF_TOPOLOGY_SOURCESTREAM_NODE:
753 if (node->u.source.source)
754 IMFMediaSource_Release(node->u.source.source);
755 break;
756 case MF_TOPOLOGY_TRANSFORM_NODE:
757 for (i = 0; i < node->u.transform.input_count; ++i)
758 transform_stream_drop_samples(&node->u.transform.inputs[i]);
759 for (i = 0; i < node->u.transform.output_count; ++i)
760 transform_stream_drop_samples(&node->u.transform.outputs[i]);
761 heap_free(node->u.transform.inputs);
762 heap_free(node->u.transform.outputs);
763 heap_free(node->u.transform.input_map);
764 heap_free(node->u.transform.output_map);
765 break;
766 case MF_TOPOLOGY_OUTPUT_NODE:
767 if (node->u.sink.allocator)
768 IMFVideoSampleAllocator_Release(node->u.sink.allocator);
769 if (node->u.sink.allocator_cb)
771 IMFVideoSampleAllocatorCallback_SetCallback(node->u.sink.allocator_cb, NULL);
772 IMFVideoSampleAllocatorCallback_Release(node->u.sink.allocator_cb);
774 break;
775 default:
779 if (node->object.object)
780 IUnknown_Release(node->object.object);
781 if (node->node)
782 IMFTopologyNode_Release(node->node);
783 heap_free(node);
786 static void session_clear_presentation(struct media_session *session)
788 struct media_source *source, *source2;
789 struct media_sink *sink, *sink2;
790 struct topo_node *node, *node2;
791 struct session_op *op, *op2;
793 IMFTopology_Clear(session->presentation.current_topology);
794 session->presentation.topo_status = MF_TOPOSTATUS_INVALID;
796 LIST_FOR_EACH_ENTRY_SAFE(source, source2, &session->presentation.sources, struct media_source, entry)
798 list_remove(&source->entry);
799 if (source->source)
800 IMFMediaSource_Release(source->source);
801 if (source->pd)
802 IMFPresentationDescriptor_Release(source->pd);
803 heap_free(source);
806 LIST_FOR_EACH_ENTRY_SAFE(node, node2, &session->presentation.nodes, struct topo_node, entry)
808 list_remove(&node->entry);
809 release_topo_node(node);
812 LIST_FOR_EACH_ENTRY_SAFE(sink, sink2, &session->presentation.sinks, struct media_sink, entry)
814 list_remove(&sink->entry);
816 if (sink->sink)
817 IMFMediaSink_Release(sink->sink);
818 if (sink->preroll)
819 IMFMediaSinkPreroll_Release(sink->preroll);
820 if (sink->event_generator)
821 IMFMediaEventGenerator_Release(sink->event_generator);
822 heap_free(sink);
825 LIST_FOR_EACH_ENTRY_SAFE(op, op2, &session->commands, struct session_op, entry)
827 list_remove(&op->entry);
828 IUnknown_Release(&op->IUnknown_iface);
832 static struct topo_node *session_get_node_by_id(const struct media_session *session, TOPOID id)
834 struct topo_node *node;
836 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
838 if (node->node_id == id)
839 return node;
842 return NULL;
845 static void session_start(struct media_session *session, const GUID *time_format, const PROPVARIANT *start_position)
847 struct media_source *source;
848 HRESULT hr;
850 switch (session->state)
852 case SESSION_STATE_STOPPED:
853 case SESSION_STATE_PAUSED:
855 session->presentation.time_format = *time_format;
856 session->presentation.start_position.vt = VT_EMPTY;
857 PropVariantCopy(&session->presentation.start_position, start_position);
859 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
861 if (!(session->presentation.flags & SESSION_FLAG_SOURCES_SUBSCRIBED))
863 if (FAILED(hr = IMFMediaSource_BeginGetEvent(source->source, &session->events_callback,
864 (IUnknown *)source->source)))
866 WARN("Failed to subscribe to source events, hr %#x.\n", hr);
870 if (FAILED(hr = IMFMediaSource_Start(source->source, source->pd, &GUID_NULL, start_position)))
871 WARN("Failed to start media source %p, hr %#x.\n", source->source, hr);
874 session->presentation.flags |= SESSION_FLAG_SOURCES_SUBSCRIBED;
875 session->state = SESSION_STATE_STARTING_SOURCES;
876 break;
877 case SESSION_STATE_STARTED:
878 FIXME("Seeking is not implemented.\n");
879 break;
880 case SESSION_STATE_CLOSED:
881 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStarted, &GUID_NULL,
882 MF_E_INVALIDREQUEST, NULL);
883 break;
884 default:
889 static void session_command_complete(struct media_session *session)
891 struct session_op *op;
892 struct list *e;
894 /* Pop current command, submit next. */
895 if ((e = list_head(&session->commands)))
897 op = LIST_ENTRY(e, struct session_op, entry);
898 list_remove(&op->entry);
899 IUnknown_Release(&op->IUnknown_iface);
902 if ((e = list_head(&session->commands)))
904 op = LIST_ENTRY(e, struct session_op, entry);
905 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface);
909 static void session_set_started(struct media_session *session)
911 struct media_source *source;
912 unsigned int caps, flags;
913 IMFMediaEvent *event;
915 session->state = SESSION_STATE_STARTED;
917 caps = session->caps | MFSESSIONCAP_PAUSE;
919 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
921 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source->source, &flags)))
923 if (!(flags & MFMEDIASOURCE_CAN_PAUSE))
925 caps &= ~MFSESSIONCAP_PAUSE;
926 break;
931 session_set_caps(session, caps);
933 if (SUCCEEDED(MFCreateMediaEvent(MESessionStarted, &GUID_NULL, S_OK, NULL, &event)))
935 IMFMediaEvent_SetUINT64(event, &MF_EVENT_PRESENTATION_TIME_OFFSET, 0);
936 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
937 IMFMediaEvent_Release(event);
939 session_command_complete(session);
942 static void session_set_paused(struct media_session *session, HRESULT status)
944 session->state = SESSION_STATE_PAUSED;
945 if (SUCCEEDED(status))
946 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
947 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionPaused, &GUID_NULL, status, NULL);
948 session_command_complete(session);
951 static void session_set_closed(struct media_session *session, HRESULT status)
953 session->state = SESSION_STATE_CLOSED;
954 if (SUCCEEDED(status))
955 session_set_caps(session, session->caps & ~(MFSESSIONCAP_START | MFSESSIONCAP_SEEK));
956 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionClosed, &GUID_NULL, status, NULL);
957 session_command_complete(session);
960 static void session_pause(struct media_session *session)
962 HRESULT hr;
964 switch (session->state)
966 case SESSION_STATE_STARTED:
968 /* Transition in two steps - pause clock, wait for sinks and pause sources. */
969 if (SUCCEEDED(hr = IMFPresentationClock_Pause(session->clock)))
970 session->state = SESSION_STATE_PAUSING_SINKS;
972 break;
973 default:
974 hr = MF_E_INVALIDREQUEST;
977 if (FAILED(hr))
978 session_set_paused(session, hr);
981 static void session_set_stopped(struct media_session *session, HRESULT status)
983 MediaEventType event_type;
984 IMFMediaEvent *event;
986 session->state = SESSION_STATE_STOPPED;
987 event_type = session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION ? MESessionEnded : MESessionStopped;
989 if (SUCCEEDED(MFCreateMediaEvent(event_type, &GUID_NULL, status, NULL, &event)))
991 IMFMediaEvent_SetUINT64(event, &MF_SESSION_APPROX_EVENT_OCCURRENCE_TIME, session->presentation.clock_stop_time);
992 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
993 IMFMediaEvent_Release(event);
995 session_command_complete(session);
998 static void session_stop(struct media_session *session)
1000 HRESULT hr = MF_E_INVALIDREQUEST;
1002 switch (session->state)
1004 case SESSION_STATE_STARTED:
1005 case SESSION_STATE_PAUSED:
1007 /* Transition in two steps - pause clock, wait for sinks and pause sources. */
1008 IMFPresentationClock_GetTime(session->clock, &session->presentation.clock_stop_time);
1009 if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock)))
1010 session->state = SESSION_STATE_STOPPING_SINKS;
1011 else
1012 session_set_stopped(session, hr);
1014 break;
1015 case SESSION_STATE_STOPPED:
1016 hr = S_OK;
1017 /* fallthrough */
1018 default:
1019 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStopped, &GUID_NULL, hr, NULL);
1020 session_command_complete(session);
1021 break;
1025 static HRESULT session_finalize_sinks(struct media_session *session)
1027 IMFFinalizableMediaSink *fin_sink;
1028 BOOL sinks_finalized = TRUE;
1029 struct media_sink *sink;
1030 HRESULT hr = S_OK;
1032 session->presentation.flags &= ~SESSION_FLAG_FINALIZE_SINKS;
1033 session->state = SESSION_STATE_FINALIZING_SINKS;
1035 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
1037 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink->sink, &IID_IMFFinalizableMediaSink, (void **)&fin_sink)))
1039 hr = IMFFinalizableMediaSink_BeginFinalize(fin_sink, &session->sink_finalizer_callback,
1040 (IUnknown *)fin_sink);
1041 IMFFinalizableMediaSink_Release(fin_sink);
1042 if (FAILED(hr))
1043 break;
1044 sinks_finalized = FALSE;
1046 else
1047 sink->finalized = TRUE;
1050 if (sinks_finalized)
1051 session_set_closed(session, hr);
1053 return hr;
1056 static void session_close(struct media_session *session)
1058 HRESULT hr = S_OK;
1060 switch (session->state)
1062 case SESSION_STATE_STOPPED:
1063 hr = session_finalize_sinks(session);
1064 break;
1065 case SESSION_STATE_STARTED:
1066 case SESSION_STATE_PAUSED:
1067 session->presentation.flags |= SESSION_FLAG_FINALIZE_SINKS;
1068 if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock)))
1069 session->state = SESSION_STATE_STOPPING_SINKS;
1070 break;
1071 default:
1072 hr = MF_E_INVALIDREQUEST;
1073 break;
1076 if (FAILED(hr))
1077 session_set_closed(session, hr);
1080 static struct media_source *session_get_media_source(struct media_session *session, IMFMediaSource *source)
1082 struct media_source *cur;
1084 LIST_FOR_EACH_ENTRY(cur, &session->presentation.sources, struct media_source, entry)
1086 if (source == cur->source)
1087 return cur;
1090 return NULL;
1093 static void session_release_media_source(struct media_source *source)
1095 IMFMediaSource_Release(source->source);
1096 if (source->pd)
1097 IMFPresentationDescriptor_Release(source->pd);
1098 heap_free(source);
1101 static HRESULT session_add_media_source(struct media_session *session, IMFTopologyNode *node, IMFMediaSource *source)
1103 struct media_source *media_source;
1104 HRESULT hr;
1106 if (session_get_media_source(session, source))
1107 return S_FALSE;
1109 if (!(media_source = heap_alloc_zero(sizeof(*media_source))))
1110 return E_OUTOFMEMORY;
1112 media_source->source = source;
1113 IMFMediaSource_AddRef(media_source->source);
1115 hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, &IID_IMFPresentationDescriptor,
1116 (void **)&media_source->pd);
1118 if (SUCCEEDED(hr))
1119 list_add_tail(&session->presentation.sources, &media_source->entry);
1120 else
1121 session_release_media_source(media_source);
1123 return hr;
1126 static void session_raise_topology_set(struct media_session *session, IMFTopology *topology, HRESULT status)
1128 PROPVARIANT param;
1130 param.vt = topology ? VT_UNKNOWN : VT_EMPTY;
1131 param.punkVal = (IUnknown *)topology;
1133 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologySet, &GUID_NULL, status, &param);
1136 static DWORD session_get_object_rate_caps(IUnknown *object)
1138 IMFRateSupport *rate_support;
1139 DWORD caps = 0;
1140 float rate;
1142 if (SUCCEEDED(MFGetService(object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support)))
1144 rate = 0.0f;
1145 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support, MFRATE_FORWARD, TRUE, &rate)) && rate != 0.0f)
1146 caps |= MFSESSIONCAP_RATE_FORWARD;
1148 rate = 0.0f;
1149 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support, MFRATE_REVERSE, TRUE, &rate)) && rate != 0.0f)
1150 caps |= MFSESSIONCAP_RATE_REVERSE;
1152 IMFRateSupport_Release(rate_support);
1155 return caps;
1158 static HRESULT session_add_media_sink(struct media_session *session, IMFTopologyNode *node, IMFMediaSink *sink)
1160 struct media_sink *media_sink;
1161 DWORD flags;
1163 LIST_FOR_EACH_ENTRY(media_sink, &session->presentation.sinks, struct media_sink, entry)
1165 if (sink == media_sink->sink)
1166 return S_FALSE;
1169 if (!(media_sink = heap_alloc_zero(sizeof(*media_sink))))
1170 return E_OUTOFMEMORY;
1172 media_sink->sink = sink;
1173 IMFMediaSink_AddRef(media_sink->sink);
1175 IMFMediaSink_QueryInterface(media_sink->sink, &IID_IMFMediaEventGenerator, (void **)&media_sink->event_generator);
1177 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink, &flags)) && flags & MEDIASINK_CAN_PREROLL)
1179 if (SUCCEEDED(IMFMediaSink_QueryInterface(media_sink->sink, &IID_IMFMediaSinkPreroll, (void **)&media_sink->preroll)))
1180 session->presentation.flags |= SESSION_FLAG_NEEDS_PREROLL;
1183 list_add_tail(&session->presentation.sinks, &media_sink->entry);
1185 return S_OK;
1188 static HRESULT session_set_transform_stream_info(struct topo_node *node)
1190 unsigned int *input_map = NULL, *output_map = NULL;
1191 unsigned int i, input_count, output_count;
1192 struct transform_stream *streams;
1193 HRESULT hr;
1195 hr = IMFTransform_GetStreamCount(node->object.transform, &input_count, &output_count);
1196 if (SUCCEEDED(hr) && (input_count > 1 || output_count > 1))
1198 input_map = heap_calloc(input_count, sizeof(*input_map));
1199 output_map = heap_calloc(output_count, sizeof(*output_map));
1200 if (FAILED(IMFTransform_GetStreamIDs(node->object.transform, input_count, input_map,
1201 output_count, output_map)))
1203 /* Assume sequential identifiers. */
1204 heap_free(input_map);
1205 heap_free(output_map);
1206 input_map = output_map = NULL;
1210 if (SUCCEEDED(hr))
1212 streams = heap_calloc(input_count, sizeof(*streams));
1213 for (i = 0; i < input_count; ++i)
1214 list_init(&streams[i].samples);
1215 node->u.transform.inputs = streams;
1217 streams = heap_calloc(output_count, sizeof(*streams));
1218 for (i = 0; i < output_count; ++i)
1219 list_init(&streams[i].samples);
1220 node->u.transform.outputs = streams;
1222 node->u.transform.input_count = input_count;
1223 node->u.transform.output_count = output_count;
1224 node->u.transform.input_map = input_map;
1225 node->u.transform.output_map = output_map;
1228 return hr;
1231 static HRESULT session_get_stream_sink_type(IMFStreamSink *sink, IMFMediaType **media_type)
1233 IMFMediaTypeHandler *handler;
1234 HRESULT hr;
1236 if (SUCCEEDED(hr = IMFStreamSink_GetMediaTypeHandler(sink, &handler)))
1238 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, media_type);
1239 IMFMediaTypeHandler_Release(handler);
1242 return hr;
1245 static HRESULT WINAPI node_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify *iface,
1246 REFIID riid, void **obj)
1248 if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorNotify) ||
1249 IsEqualIID(riid, &IID_IUnknown))
1251 *obj = iface;
1252 IMFVideoSampleAllocatorNotify_AddRef(iface);
1253 return S_OK;
1256 *obj = NULL;
1257 return E_NOINTERFACE;
1260 static ULONG WINAPI node_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify *iface)
1262 return 2;
1265 static ULONG WINAPI node_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify *iface)
1267 return 1;
1270 static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output);
1272 static HRESULT WINAPI node_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify *iface)
1274 struct topo_node *topo_node = impl_node_from_IMFVideoSampleAllocatorNotify(iface);
1275 struct session_op *op;
1277 if (SUCCEEDED(create_session_op(SESSION_CMD_SA_READY, &op)))
1279 op->u.sa_ready.node_id = topo_node->node_id;
1280 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &topo_node->session->commands_callback, &op->IUnknown_iface);
1281 IUnknown_Release(&op->IUnknown_iface);
1284 return S_OK;
1287 static const IMFVideoSampleAllocatorNotifyVtbl node_sample_allocator_cb_vtbl =
1289 node_sample_allocator_cb_QueryInterface,
1290 node_sample_allocator_cb_AddRef,
1291 node_sample_allocator_cb_Release,
1292 node_sample_allocator_cb_NotifyRelease,
1295 static HRESULT session_append_node(struct media_session *session, IMFTopologyNode *node)
1297 struct topo_node *topo_node;
1298 IMFMediaSink *media_sink;
1299 IMFMediaType *media_type;
1300 IMFStreamDescriptor *sd;
1301 HRESULT hr = S_OK;
1302 IUnknown *object;
1304 if (!(topo_node = heap_alloc_zero(sizeof(*topo_node))))
1305 return E_OUTOFMEMORY;
1307 IMFTopologyNode_GetNodeType(node, &topo_node->type);
1308 IMFTopologyNode_GetTopoNodeID(node, &topo_node->node_id);
1309 topo_node->node = node;
1310 IMFTopologyNode_AddRef(topo_node->node);
1311 topo_node->session = session;
1313 switch (topo_node->type)
1315 case MF_TOPOLOGY_OUTPUT_NODE:
1316 topo_node->u.sink.notify_cb.lpVtbl = &node_sample_allocator_cb_vtbl;
1318 if (FAILED(hr = IMFTopologyNode_GetObject(node, &object)))
1320 WARN("Node %s does not have associated object.\n", wine_dbgstr_longlong(topo_node->node_id));
1321 break;
1323 hr = IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&topo_node->object.object);
1324 IUnknown_Release(object);
1325 if (FAILED(hr))
1326 break;
1328 if (FAILED(hr = IMFStreamSink_GetMediaSink(topo_node->object.sink_stream, &media_sink)))
1329 break;
1331 if (SUCCEEDED(hr = session_add_media_sink(session, node, media_sink)))
1333 if (SUCCEEDED(session_get_stream_sink_type(topo_node->object.sink_stream, &media_type)))
1335 if (SUCCEEDED(MFGetService(topo_node->object.object, &MR_VIDEO_ACCELERATION_SERVICE,
1336 &IID_IMFVideoSampleAllocator, (void **)&topo_node->u.sink.allocator)))
1338 IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node->u.sink.allocator, 2, media_type);
1339 IMFVideoSampleAllocator_QueryInterface(topo_node->u.sink.allocator,
1340 &IID_IMFVideoSampleAllocatorCallback, (void **)&topo_node->u.sink.allocator_cb);
1341 IMFVideoSampleAllocatorCallback_SetCallback(topo_node->u.sink.allocator_cb,
1342 &topo_node->u.sink.notify_cb);
1344 IMFMediaType_Release(media_type);
1347 IMFMediaSink_Release(media_sink);
1349 break;
1350 case MF_TOPOLOGY_SOURCESTREAM_NODE:
1351 if (FAILED(IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_SOURCE, &IID_IMFMediaSource,
1352 (void **)&topo_node->u.source.source)))
1354 WARN("Missing MF_TOPONODE_SOURCE, hr %#x.\n", hr);
1355 break;
1358 if (FAILED(hr = session_add_media_source(session, node, topo_node->u.source.source)))
1359 break;
1361 if (FAILED(hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR,
1362 &IID_IMFStreamDescriptor, (void **)&sd)))
1364 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#x.\n", hr);
1365 break;
1368 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &topo_node->u.source.stream_id);
1369 IMFStreamDescriptor_Release(sd);
1371 break;
1372 case MF_TOPOLOGY_TRANSFORM_NODE:
1373 if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object)))
1375 hr = IUnknown_QueryInterface(object, &IID_IMFTransform, (void **)&topo_node->object.transform);
1376 IUnknown_Release(object);
1379 if (SUCCEEDED(hr))
1380 hr = session_set_transform_stream_info(topo_node);
1381 else
1382 WARN("Failed to get IMFTransform for MFT node, hr %#x.\n", hr);
1384 break;
1385 case MF_TOPOLOGY_TEE_NODE:
1386 FIXME("Unsupported node type %d.\n", topo_node->type);
1388 break;
1389 default:
1393 if (SUCCEEDED(hr))
1394 list_add_tail(&session->presentation.nodes, &topo_node->entry);
1395 else
1396 release_topo_node(topo_node);
1398 return hr;
1401 static HRESULT session_collect_nodes(struct media_session *session)
1403 IMFTopology *topology = session->presentation.current_topology;
1404 IMFTopologyNode *node;
1405 WORD i, count = 0;
1406 HRESULT hr;
1408 if (!list_empty(&session->presentation.nodes))
1409 return S_OK;
1411 if (FAILED(hr = IMFTopology_GetNodeCount(topology, &count)))
1412 return hr;
1414 for (i = 0; i < count; ++i)
1416 if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
1418 WARN("Failed to get node %u.\n", i);
1419 break;
1422 hr = session_append_node(session, node);
1423 IMFTopologyNode_Release(node);
1424 if (FAILED(hr))
1426 WARN("Failed to add node %u.\n", i);
1427 break;
1431 return hr;
1434 static HRESULT session_set_current_topology(struct media_session *session, IMFTopology *topology)
1436 struct media_source *source;
1437 DWORD caps, object_flags;
1438 struct media_sink *sink;
1439 struct topo_node *node;
1440 struct session_op *op;
1441 IMFMediaEvent *event;
1442 HRESULT hr;
1444 if (session->quality_manager)
1446 if (SUCCEEDED(create_session_op(SESSION_CMD_QM_NOTIFY_TOPOLOGY, &op)))
1448 op->u.notify_topology.topology = topology;
1449 IMFTopology_AddRef(op->u.notify_topology.topology);
1450 session_submit_command(session, op);
1451 IUnknown_Release(&op->IUnknown_iface);
1455 if (FAILED(hr = IMFTopology_CloneFrom(session->presentation.current_topology, topology)))
1457 WARN("Failed to clone topology, hr %#x.\n", hr);
1458 return hr;
1461 session_collect_nodes(session);
1463 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
1465 if (node->type == MF_TOPOLOGY_TRANSFORM_NODE)
1467 if (FAILED(hr = IMFTransform_ProcessMessage(node->object.transform,
1468 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0)))
1469 return hr;
1473 /* FIXME: attributes are all zero for now */
1474 if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime, &GUID_NULL, S_OK, NULL, &event)))
1476 IMFMediaEvent_SetUINT64(event, &MF_EVENT_START_PRESENTATION_TIME, 0);
1477 IMFMediaEvent_SetUINT64(event, &MF_EVENT_PRESENTATION_TIME_OFFSET, 0);
1478 IMFMediaEvent_SetUINT64(event, &MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT, 0);
1480 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
1481 IMFMediaEvent_Release(event);
1484 /* Update session caps. */
1485 caps = MFSESSIONCAP_START | MFSESSIONCAP_SEEK | MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE |
1486 MFSESSIONCAP_DOES_NOT_USE_NETWORK;
1488 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
1490 if (!caps)
1491 break;
1493 object_flags = 0;
1494 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source->source, &object_flags)))
1496 if (!(object_flags & MFMEDIASOURCE_DOES_NOT_USE_NETWORK))
1497 caps &= ~MFSESSIONCAP_DOES_NOT_USE_NETWORK;
1498 if (!(object_flags & MFMEDIASOURCE_CAN_SEEK))
1499 caps &= ~MFSESSIONCAP_SEEK;
1502 /* Mask unsupported rate caps. */
1504 caps &= session_get_object_rate_caps((IUnknown *)source->source)
1505 | ~(MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE);
1508 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
1510 if (!caps)
1511 break;
1513 object_flags = 0;
1514 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink->sink, &object_flags)))
1516 if (!(object_flags & MEDIASINK_RATELESS))
1517 caps &= session_get_object_rate_caps((IUnknown *)sink->sink)
1518 | ~(MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE);
1522 session_set_caps(session, caps);
1524 return S_OK;
1527 static void session_set_topology(struct media_session *session, DWORD flags, IMFTopology *topology)
1529 IMFTopology *resolved_topology = NULL;
1530 HRESULT hr = S_OK;
1532 /* Resolve unless claimed to be full. */
1533 if (!(flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT) && topology)
1535 if (!(flags & MFSESSION_SETTOPOLOGY_NORESOLUTION))
1537 hr = session_bind_output_nodes(topology);
1539 if (SUCCEEDED(hr))
1540 hr = IMFTopoLoader_Load(session->topo_loader, topology, &resolved_topology, NULL /* FIXME? */);
1542 if (SUCCEEDED(hr))
1544 topology = resolved_topology;
1549 if (flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT)
1551 if ((topology && topology == session->presentation.current_topology) || !topology)
1553 /* FIXME: stop current topology, queue next one. */
1554 session_clear_presentation(session);
1556 else
1557 hr = S_FALSE;
1559 topology = NULL;
1561 else if (topology && flags & MFSESSION_SETTOPOLOGY_IMMEDIATE)
1563 session_clear_topologies(session);
1564 session_clear_presentation(session);
1567 session_raise_topology_set(session, topology, hr);
1569 /* With no current topology set it right away, otherwise queue. */
1570 if (topology)
1572 struct queued_topology *queued_topology;
1574 if ((queued_topology = heap_alloc_zero(sizeof(*queued_topology))))
1576 queued_topology->topology = topology;
1577 IMFTopology_AddRef(queued_topology->topology);
1579 list_add_tail(&session->topologies, &queued_topology->entry);
1582 if (session->presentation.topo_status == MF_TOPOSTATUS_INVALID)
1584 hr = session_set_current_topology(session, topology);
1585 session_set_topo_status(session, hr, MF_TOPOSTATUS_READY);
1589 if (resolved_topology)
1590 IMFTopology_Release(resolved_topology);
1593 static HRESULT WINAPI mfsession_QueryInterface(IMFMediaSession *iface, REFIID riid, void **out)
1595 struct media_session *session = impl_from_IMFMediaSession(iface);
1597 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1599 if (IsEqualIID(riid, &IID_IMFMediaSession) ||
1600 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
1601 IsEqualIID(riid, &IID_IUnknown))
1603 *out = &session->IMFMediaSession_iface;
1604 IMFMediaSession_AddRef(iface);
1605 return S_OK;
1607 else if (IsEqualIID(riid, &IID_IMFGetService))
1609 *out = &session->IMFGetService_iface;
1610 IMFMediaSession_AddRef(iface);
1611 return S_OK;
1614 WARN("Unsupported %s.\n", debugstr_guid(riid));
1615 *out = NULL;
1616 return E_NOINTERFACE;
1619 static ULONG WINAPI mfsession_AddRef(IMFMediaSession *iface)
1621 struct media_session *session = impl_from_IMFMediaSession(iface);
1622 ULONG refcount = InterlockedIncrement(&session->refcount);
1624 TRACE("%p, refcount %u.\n", iface, refcount);
1626 return refcount;
1629 static ULONG WINAPI mfsession_Release(IMFMediaSession *iface)
1631 struct media_session *session = impl_from_IMFMediaSession(iface);
1632 ULONG refcount = InterlockedDecrement(&session->refcount);
1634 TRACE("%p, refcount %u.\n", iface, refcount);
1636 if (!refcount)
1638 session_clear_topologies(session);
1639 session_clear_presentation(session);
1640 if (session->presentation.current_topology)
1641 IMFTopology_Release(session->presentation.current_topology);
1642 if (session->event_queue)
1643 IMFMediaEventQueue_Release(session->event_queue);
1644 if (session->clock)
1645 IMFPresentationClock_Release(session->clock);
1646 if (session->system_time_source)
1647 IMFPresentationTimeSource_Release(session->system_time_source);
1648 if (session->clock_rate_control)
1649 IMFRateControl_Release(session->clock_rate_control);
1650 if (session->topo_loader)
1651 IMFTopoLoader_Release(session->topo_loader);
1652 if (session->quality_manager)
1653 IMFQualityManager_Release(session->quality_manager);
1654 DeleteCriticalSection(&session->cs);
1655 heap_free(session);
1658 return refcount;
1661 static HRESULT WINAPI mfsession_GetEvent(IMFMediaSession *iface, DWORD flags, IMFMediaEvent **event)
1663 struct media_session *session = impl_from_IMFMediaSession(iface);
1665 TRACE("%p, %#x, %p.\n", iface, flags, event);
1667 return IMFMediaEventQueue_GetEvent(session->event_queue, flags, event);
1670 static HRESULT WINAPI mfsession_BeginGetEvent(IMFMediaSession *iface, IMFAsyncCallback *callback, IUnknown *state)
1672 struct media_session *session = impl_from_IMFMediaSession(iface);
1674 TRACE("%p, %p, %p.\n", iface, callback, state);
1676 return IMFMediaEventQueue_BeginGetEvent(session->event_queue, callback, state);
1679 static HRESULT WINAPI mfsession_EndGetEvent(IMFMediaSession *iface, IMFAsyncResult *result, IMFMediaEvent **event)
1681 struct media_session *session = impl_from_IMFMediaSession(iface);
1683 TRACE("%p, %p, %p.\n", iface, result, event);
1685 return IMFMediaEventQueue_EndGetEvent(session->event_queue, result, event);
1688 static HRESULT WINAPI mfsession_QueueEvent(IMFMediaSession *iface, MediaEventType event_type, REFGUID ext_type,
1689 HRESULT hr, const PROPVARIANT *value)
1691 struct media_session *session = impl_from_IMFMediaSession(iface);
1693 TRACE("%p, %d, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
1695 return IMFMediaEventQueue_QueueEventParamVar(session->event_queue, event_type, ext_type, hr, value);
1698 static HRESULT WINAPI mfsession_SetTopology(IMFMediaSession *iface, DWORD flags, IMFTopology *topology)
1700 struct media_session *session = impl_from_IMFMediaSession(iface);
1701 struct session_op *op;
1702 WORD node_count = 0;
1703 HRESULT hr;
1705 TRACE("%p, %#x, %p.\n", iface, flags, topology);
1707 if (topology)
1709 if (FAILED(IMFTopology_GetNodeCount(topology, &node_count)) || node_count == 0)
1710 return E_INVALIDARG;
1713 if (FAILED(hr = create_session_op(SESSION_CMD_SET_TOPOLOGY, &op)))
1714 return hr;
1716 op->u.set_topology.flags = flags;
1717 op->u.set_topology.topology = topology;
1718 if (op->u.set_topology.topology)
1719 IMFTopology_AddRef(op->u.set_topology.topology);
1721 hr = session_submit_command(session, op);
1722 IUnknown_Release(&op->IUnknown_iface);
1724 return hr;
1727 static HRESULT WINAPI mfsession_ClearTopologies(IMFMediaSession *iface)
1729 struct media_session *session = impl_from_IMFMediaSession(iface);
1731 TRACE("%p.\n", iface);
1733 return session_submit_simple_command(session, SESSION_CMD_CLEAR_TOPOLOGIES);
1736 static HRESULT WINAPI mfsession_Start(IMFMediaSession *iface, const GUID *format, const PROPVARIANT *start_position)
1738 struct media_session *session = impl_from_IMFMediaSession(iface);
1739 struct session_op *op;
1740 HRESULT hr;
1742 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), start_position);
1744 if (!start_position)
1745 return E_POINTER;
1747 if (FAILED(hr = create_session_op(SESSION_CMD_START, &op)))
1748 return hr;
1750 op->u.start.time_format = format ? *format : GUID_NULL;
1751 hr = PropVariantCopy(&op->u.start.start_position, start_position);
1753 if (SUCCEEDED(hr))
1754 hr = session_submit_command(session, op);
1756 IUnknown_Release(&op->IUnknown_iface);
1758 return hr;
1761 static HRESULT WINAPI mfsession_Pause(IMFMediaSession *iface)
1763 struct media_session *session = impl_from_IMFMediaSession(iface);
1765 TRACE("%p.\n", iface);
1767 return session_submit_simple_command(session, SESSION_CMD_PAUSE);
1770 static HRESULT WINAPI mfsession_Stop(IMFMediaSession *iface)
1772 struct media_session *session = impl_from_IMFMediaSession(iface);
1774 TRACE("%p.\n", iface);
1776 return session_submit_simple_command(session, SESSION_CMD_STOP);
1779 static HRESULT WINAPI mfsession_Close(IMFMediaSession *iface)
1781 struct media_session *session = impl_from_IMFMediaSession(iface);
1783 TRACE("%p.\n", iface);
1785 return session_submit_simple_command(session, SESSION_CMD_CLOSE);
1788 static HRESULT WINAPI mfsession_Shutdown(IMFMediaSession *iface)
1790 struct media_session *session = impl_from_IMFMediaSession(iface);
1791 HRESULT hr = S_OK;
1793 FIXME("%p.\n", iface);
1795 EnterCriticalSection(&session->cs);
1796 if (SUCCEEDED(hr = session_is_shut_down(session)))
1798 session->state = SESSION_STATE_SHUT_DOWN;
1799 IMFMediaEventQueue_Shutdown(session->event_queue);
1800 if (session->quality_manager)
1801 IMFQualityManager_Shutdown(session->quality_manager);
1802 MFShutdownObject((IUnknown *)session->clock);
1803 IMFPresentationClock_Release(session->clock);
1804 session->clock = NULL;
1806 LeaveCriticalSection(&session->cs);
1808 return hr;
1811 static HRESULT WINAPI mfsession_GetClock(IMFMediaSession *iface, IMFClock **clock)
1813 struct media_session *session = impl_from_IMFMediaSession(iface);
1814 HRESULT hr;
1816 TRACE("%p, %p.\n", iface, clock);
1818 EnterCriticalSection(&session->cs);
1819 if (SUCCEEDED(hr = session_is_shut_down(session)))
1821 *clock = (IMFClock *)session->clock;
1822 IMFClock_AddRef(*clock);
1824 LeaveCriticalSection(&session->cs);
1826 return hr;
1829 static HRESULT WINAPI mfsession_GetSessionCapabilities(IMFMediaSession *iface, DWORD *caps)
1831 struct media_session *session = impl_from_IMFMediaSession(iface);
1832 HRESULT hr = S_OK;
1834 TRACE("%p, %p.\n", iface, caps);
1836 if (!caps)
1837 return E_POINTER;
1839 EnterCriticalSection(&session->cs);
1840 if (SUCCEEDED(hr = session_is_shut_down(session)))
1841 *caps = session->caps;
1842 LeaveCriticalSection(&session->cs);
1844 return hr;
1847 static HRESULT WINAPI mfsession_GetFullTopology(IMFMediaSession *iface, DWORD flags, TOPOID id, IMFTopology **topology)
1849 struct media_session *session = impl_from_IMFMediaSession(iface);
1850 struct queued_topology *queued;
1851 TOPOID topo_id;
1852 HRESULT hr;
1854 TRACE("%p, %#x, %s, %p.\n", iface, flags, wine_dbgstr_longlong(id), topology);
1856 *topology = NULL;
1858 EnterCriticalSection(&session->cs);
1860 if (SUCCEEDED(hr = session_is_shut_down(session)))
1862 if (flags & MFSESSION_GETFULLTOPOLOGY_CURRENT)
1864 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
1865 *topology = session->presentation.current_topology;
1866 else
1867 hr = MF_E_INVALIDREQUEST;
1869 else
1871 LIST_FOR_EACH_ENTRY(queued, &session->topologies, struct queued_topology, entry)
1873 if (SUCCEEDED(IMFTopology_GetTopologyID(queued->topology, &topo_id)) && topo_id == id)
1875 *topology = queued->topology;
1876 break;
1881 if (*topology)
1882 IMFTopology_AddRef(*topology);
1885 LeaveCriticalSection(&session->cs);
1887 return hr;
1890 static const IMFMediaSessionVtbl mfmediasessionvtbl =
1892 mfsession_QueryInterface,
1893 mfsession_AddRef,
1894 mfsession_Release,
1895 mfsession_GetEvent,
1896 mfsession_BeginGetEvent,
1897 mfsession_EndGetEvent,
1898 mfsession_QueueEvent,
1899 mfsession_SetTopology,
1900 mfsession_ClearTopologies,
1901 mfsession_Start,
1902 mfsession_Pause,
1903 mfsession_Stop,
1904 mfsession_Close,
1905 mfsession_Shutdown,
1906 mfsession_GetClock,
1907 mfsession_GetSessionCapabilities,
1908 mfsession_GetFullTopology,
1911 static HRESULT WINAPI session_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1913 struct media_session *session = impl_from_IMFGetService(iface);
1914 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
1917 static ULONG WINAPI session_get_service_AddRef(IMFGetService *iface)
1919 struct media_session *session = impl_from_IMFGetService(iface);
1920 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
1923 static ULONG WINAPI session_get_service_Release(IMFGetService *iface)
1925 struct media_session *session = impl_from_IMFGetService(iface);
1926 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
1929 static HRESULT WINAPI session_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
1931 struct media_session *session = impl_from_IMFGetService(iface);
1933 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1935 *obj = NULL;
1937 if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE))
1939 if (IsEqualIID(riid, &IID_IMFRateSupport))
1941 *obj = &session->IMFRateSupport_iface;
1943 else if (IsEqualIID(riid, &IID_IMFRateControl))
1945 *obj = &session->IMFRateControl_iface;
1948 else if (IsEqualGUID(service, &MF_LOCAL_MFT_REGISTRATION_SERVICE))
1950 return IMFLocalMFTRegistration_QueryInterface(&local_mft_registration, riid, obj);
1952 else if (IsEqualGUID(service, &MR_VIDEO_RENDER_SERVICE))
1954 IMFStreamSink *stream_sink;
1955 IMFTopologyNode *node;
1956 IUnknown *vr, *object;
1957 IMFCollection *nodes;
1958 IMFMediaSink *sink;
1959 unsigned int i = 0;
1960 HRESULT hr;
1962 EnterCriticalSection(&session->cs);
1964 /* Use first sink to support IMFVideoRenderer. */
1965 if (session->presentation.current_topology)
1967 if (SUCCEEDED(IMFTopology_GetOutputNodeCollection(session->presentation.current_topology,
1968 &nodes)))
1970 while (IMFCollection_GetElement(nodes, i++, (IUnknown **)&node) == S_OK)
1972 if (SUCCEEDED(IMFTopologyNode_GetObject(node, &object)))
1974 if (SUCCEEDED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&stream_sink)))
1976 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink)))
1978 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink, &IID_IMFVideoRenderer, (void **)&vr)))
1980 if (FAILED(hr = MFGetService(vr, service, riid, obj)))
1981 WARN("Failed to get service from video renderer %#x.\n", hr);
1982 IUnknown_Release(vr);
1985 IMFStreamSink_Release(stream_sink);
1988 IUnknown_Release(object);
1991 IMFTopologyNode_Release(node);
1993 if (*obj)
1994 break;
1997 IMFCollection_Release(nodes);
2001 LeaveCriticalSection(&session->cs);
2003 else
2004 FIXME("Unsupported service %s.\n", debugstr_guid(service));
2006 if (*obj)
2007 IUnknown_AddRef((IUnknown *)*obj);
2009 return *obj ? S_OK : E_NOINTERFACE;
2012 static const IMFGetServiceVtbl session_get_service_vtbl =
2014 session_get_service_QueryInterface,
2015 session_get_service_AddRef,
2016 session_get_service_Release,
2017 session_get_service_GetService,
2020 static HRESULT WINAPI session_commands_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
2022 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
2023 IsEqualIID(riid, &IID_IUnknown))
2025 *obj = iface;
2026 IMFAsyncCallback_AddRef(iface);
2027 return S_OK;
2030 WARN("Unsupported %s.\n", debugstr_guid(riid));
2031 *obj = NULL;
2032 return E_NOINTERFACE;
2035 static ULONG WINAPI session_commands_callback_AddRef(IMFAsyncCallback *iface)
2037 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2038 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2041 static ULONG WINAPI session_commands_callback_Release(IMFAsyncCallback *iface)
2043 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2044 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2047 static HRESULT WINAPI session_commands_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
2049 return E_NOTIMPL;
2052 static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
2054 struct session_op *op = impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result));
2055 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2056 struct topo_node *topo_node;
2057 IMFTopologyNode *upstream_node;
2058 unsigned int upstream_output;
2060 EnterCriticalSection(&session->cs);
2062 switch (op->command)
2064 case SESSION_CMD_CLEAR_TOPOLOGIES:
2065 session_clear_topologies(session);
2066 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologiesCleared, &GUID_NULL,
2067 S_OK, NULL);
2068 session_command_complete(session);
2069 break;
2070 case SESSION_CMD_SET_TOPOLOGY:
2071 session_set_topology(session, op->u.set_topology.flags, op->u.set_topology.topology);
2072 session_command_complete(session);
2073 break;
2074 case SESSION_CMD_START:
2075 session_start(session, &op->u.start.time_format, &op->u.start.start_position);
2076 break;
2077 case SESSION_CMD_PAUSE:
2078 session_pause(session);
2079 break;
2080 case SESSION_CMD_STOP:
2081 session_stop(session);
2082 break;
2083 case SESSION_CMD_CLOSE:
2084 session_close(session);
2085 break;
2086 case SESSION_CMD_QM_NOTIFY_TOPOLOGY:
2087 IMFQualityManager_NotifyTopology(session->quality_manager, op->u.notify_topology.topology);
2088 session_command_complete(session);
2089 break;
2090 case SESSION_CMD_SA_READY:
2091 topo_node = session_get_node_by_id(session, op->u.sa_ready.node_id);
2093 if (topo_node->u.sink.requests)
2095 if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node->node, 0, &upstream_node, &upstream_output)))
2097 session_request_sample_from_node(session, upstream_node, upstream_output);
2098 IMFTopologyNode_Release(upstream_node);
2101 break;
2102 default:
2106 LeaveCriticalSection(&session->cs);
2108 return S_OK;
2111 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl =
2113 session_commands_callback_QueryInterface,
2114 session_commands_callback_AddRef,
2115 session_commands_callback_Release,
2116 session_commands_callback_GetParameters,
2117 session_commands_callback_Invoke,
2120 static HRESULT WINAPI session_events_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
2122 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
2123 IsEqualIID(riid, &IID_IUnknown))
2125 *obj = iface;
2126 IMFAsyncCallback_AddRef(iface);
2127 return S_OK;
2130 WARN("Unsupported %s.\n", debugstr_guid(riid));
2131 *obj = NULL;
2132 return E_NOINTERFACE;
2135 static ULONG WINAPI session_events_callback_AddRef(IMFAsyncCallback *iface)
2137 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
2138 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2141 static ULONG WINAPI session_events_callback_Release(IMFAsyncCallback *iface)
2143 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
2144 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2147 static HRESULT WINAPI session_events_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
2149 return E_NOTIMPL;
2152 static HRESULT session_add_media_stream(struct media_session *session, IMFMediaSource *source, IMFMediaStream *stream)
2154 struct topo_node *node;
2155 IMFStreamDescriptor *sd;
2156 DWORD stream_id = 0;
2157 HRESULT hr;
2159 if (FAILED(hr = IMFMediaStream_GetStreamDescriptor(stream, &sd)))
2160 return hr;
2162 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &stream_id);
2163 IMFStreamDescriptor_Release(sd);
2164 if (FAILED(hr))
2165 return hr;
2167 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2169 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->u.source.source == source
2170 && node->u.source.stream_id == stream_id)
2172 if (node->object.source_stream)
2174 WARN("Node already has stream set.\n");
2175 return S_FALSE;
2178 node->object.source_stream = stream;
2179 IMFMediaStream_AddRef(node->object.source_stream);
2180 break;
2184 return S_OK;
2187 static BOOL session_is_source_nodes_state(struct media_session *session, enum object_state state)
2189 struct media_source *source;
2190 struct topo_node *node;
2192 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2194 if (source->state != state)
2195 return FALSE;
2198 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2200 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->state != state)
2201 return FALSE;
2204 return TRUE;
2207 static BOOL session_is_output_nodes_state(struct media_session *session, enum object_state state)
2209 struct topo_node *node;
2211 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2213 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->state != state)
2214 return FALSE;
2217 return TRUE;
2220 static enum object_state session_get_object_state_for_event(MediaEventType event)
2222 switch (event)
2224 case MESourceStarted:
2225 case MEStreamStarted:
2226 case MEStreamSinkStarted:
2227 return OBJ_STATE_STARTED;
2228 case MESourcePaused:
2229 case MEStreamPaused:
2230 case MEStreamSinkPaused:
2231 return OBJ_STATE_PAUSED;
2232 case MESourceStopped:
2233 case MEStreamStopped:
2234 case MEStreamSinkStopped:
2235 return OBJ_STATE_STOPPED;
2236 case MEStreamSinkPrerolled:
2237 return OBJ_STATE_PREROLLED;
2238 default:
2239 return OBJ_STATE_INVALID;
2243 static void session_set_consumed_clock(IUnknown *object, IMFPresentationClock *clock)
2245 IMFClockConsumer *consumer;
2247 if (SUCCEEDED(IUnknown_QueryInterface(object, &IID_IMFClockConsumer, (void **)&consumer)))
2249 IMFClockConsumer_SetPresentationClock(consumer, clock);
2250 IMFClockConsumer_Release(consumer);
2254 static void session_set_presentation_clock(struct media_session *session)
2256 IMFPresentationTimeSource *time_source = NULL;
2257 struct media_source *source;
2258 struct media_sink *sink;
2259 struct topo_node *node;
2260 HRESULT hr;
2262 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2264 if (node->type == MF_TOPOLOGY_TRANSFORM_NODE)
2265 IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
2268 if (!(session->presentation.flags & SESSION_FLAG_PRESENTATION_CLOCK_SET))
2270 /* Attempt to get time source from the sinks. */
2271 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2273 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink->sink, &IID_IMFPresentationTimeSource,
2274 (void **)&time_source)))
2275 break;
2278 if (time_source)
2280 hr = IMFPresentationClock_SetTimeSource(session->clock, time_source);
2281 IMFPresentationTimeSource_Release(time_source);
2283 else
2284 hr = IMFPresentationClock_SetTimeSource(session->clock, session->system_time_source);
2286 if (FAILED(hr))
2287 WARN("Failed to set time source, hr %#x.\n", hr);
2289 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2291 if (node->type != MF_TOPOLOGY_OUTPUT_NODE)
2292 continue;
2294 if (FAILED(hr = IMFStreamSink_BeginGetEvent(node->object.sink_stream, &session->events_callback,
2295 node->object.object)))
2297 WARN("Failed to subscribe to stream sink events, hr %#x.\n", hr);
2301 /* Set clock for all topology nodes. */
2302 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2304 session_set_consumed_clock((IUnknown *)source->source, session->clock);
2307 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2309 if (sink->event_generator && FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(sink->event_generator,
2310 &session->events_callback, (IUnknown *)sink->event_generator)))
2312 WARN("Failed to subscribe to sink events, hr %#x.\n", hr);
2315 if (FAILED(hr = IMFMediaSink_SetPresentationClock(sink->sink, session->clock)))
2316 WARN("Failed to set presentation clock for the sink, hr %#x.\n", hr);
2319 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2321 if (node->type != MF_TOPOLOGY_TRANSFORM_NODE)
2322 continue;
2324 session_set_consumed_clock(node->object.object, session->clock);
2327 session->presentation.flags |= SESSION_FLAG_PRESENTATION_CLOCK_SET;
2331 static HRESULT session_start_clock(struct media_session *session)
2333 LONGLONG start_offset = 0;
2334 HRESULT hr;
2336 if (IsEqualGUID(&session->presentation.time_format, &GUID_NULL))
2338 if (session->presentation.start_position.vt == VT_EMPTY)
2339 start_offset = PRESENTATION_CURRENT_POSITION;
2340 else if (session->presentation.start_position.vt == VT_I8)
2341 start_offset = session->presentation.start_position.hVal.QuadPart;
2342 else
2343 FIXME("Unhandled position type %d.\n", session->presentation.start_position.vt);
2345 else
2346 FIXME("Unhandled time format %s.\n", debugstr_guid(&session->presentation.time_format));
2348 if (FAILED(hr = IMFPresentationClock_Start(session->clock, start_offset)))
2349 WARN("Failed to start session clock, hr %#x.\n", hr);
2351 return hr;
2354 static struct topo_node *session_get_node_object(struct media_session *session, IUnknown *object,
2355 MF_TOPOLOGY_TYPE node_type)
2357 struct topo_node *node = NULL;
2359 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2361 if (node->type == node_type && object == node->object.object)
2362 break;
2365 return node;
2368 static BOOL session_set_node_object_state(struct media_session *session, IUnknown *object,
2369 MF_TOPOLOGY_TYPE node_type, enum object_state state)
2371 struct topo_node *node;
2372 BOOL changed = FALSE;
2374 if ((node = session_get_node_object(session, object, node_type)))
2376 changed = node->state != state;
2377 node->state = state;
2380 return changed;
2383 static void session_set_source_object_state(struct media_session *session, IUnknown *object,
2384 MediaEventType event_type)
2386 IMFStreamSink *stream_sink;
2387 struct media_source *src;
2388 struct media_sink *sink;
2389 enum object_state state;
2390 struct topo_node *node;
2391 unsigned int i, count;
2392 BOOL changed = FALSE;
2393 HRESULT hr;
2395 if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
2396 return;
2398 switch (event_type)
2400 case MESourceStarted:
2401 case MESourcePaused:
2402 case MESourceStopped:
2404 LIST_FOR_EACH_ENTRY(src, &session->presentation.sources, struct media_source, entry)
2406 if (object == (IUnknown *)src->source)
2408 changed = src->state != state;
2409 src->state = state;
2410 break;
2413 break;
2414 case MEStreamStarted:
2415 case MEStreamPaused:
2416 case MEStreamStopped:
2418 changed = session_set_node_object_state(session, object, MF_TOPOLOGY_SOURCESTREAM_NODE, state);
2419 default:
2423 if (!changed)
2424 return;
2426 switch (session->state)
2428 case SESSION_STATE_STARTING_SOURCES:
2429 if (!session_is_source_nodes_state(session, OBJ_STATE_STARTED))
2430 break;
2432 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_STARTED_SOURCE);
2434 session_set_presentation_clock(session);
2436 if (session->presentation.flags & SESSION_FLAG_NEEDS_PREROLL)
2438 MFTIME preroll_time = 0;
2440 if (session->presentation.start_position.vt == VT_I8)
2441 preroll_time = session->presentation.start_position.hVal.QuadPart;
2443 /* Mark stream sinks without prerolling support as PREROLLED to keep state test logic generic. */
2444 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2446 if (sink->preroll)
2448 /* FIXME: abort and enter error state on failure. */
2449 if (FAILED(hr = IMFMediaSinkPreroll_NotifyPreroll(sink->preroll, preroll_time)))
2450 WARN("Preroll notification failed, hr %#x.\n", hr);
2452 else
2454 if (SUCCEEDED(IMFMediaSink_GetStreamSinkCount(sink->sink, &count)))
2456 for (i = 0; i < count; ++i)
2458 if (SUCCEEDED(IMFMediaSink_GetStreamSinkByIndex(sink->sink, i, &stream_sink)))
2460 session_set_node_object_state(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE,
2461 OBJ_STATE_PREROLLED);
2462 IMFStreamSink_Release(stream_sink);
2468 session->state = SESSION_STATE_PREROLLING_SINKS;
2470 else if (SUCCEEDED(session_start_clock(session)))
2471 session->state = SESSION_STATE_STARTING_SINKS;
2473 break;
2474 case SESSION_STATE_PAUSING_SOURCES:
2475 if (!session_is_source_nodes_state(session, OBJ_STATE_PAUSED))
2476 break;
2478 session_set_paused(session, S_OK);
2479 break;
2480 case SESSION_STATE_STOPPING_SOURCES:
2481 if (!session_is_source_nodes_state(session, OBJ_STATE_STOPPED))
2482 break;
2484 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2486 switch (node->type)
2488 case MF_TOPOLOGY_OUTPUT_NODE:
2489 IMFStreamSink_Flush(node->object.sink_stream);
2490 break;
2491 case MF_TOPOLOGY_TRANSFORM_NODE:
2492 IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_COMMAND_FLUSH, 0);
2493 break;
2494 default:
2499 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
2501 if (session->presentation.flags & SESSION_FLAG_FINALIZE_SINKS)
2502 session_finalize_sinks(session);
2503 else
2504 session_set_stopped(session, S_OK);
2506 break;
2507 default:
2512 static void session_set_sink_stream_state(struct media_session *session, IMFStreamSink *stream,
2513 MediaEventType event_type)
2515 struct media_source *source;
2516 enum object_state state;
2517 HRESULT hr = S_OK;
2518 BOOL changed;
2520 if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
2521 return;
2523 if (!(changed = session_set_node_object_state(session, (IUnknown *)stream, MF_TOPOLOGY_OUTPUT_NODE, state)))
2524 return;
2526 switch (session->state)
2528 case SESSION_STATE_PREROLLING_SINKS:
2529 if (!session_is_output_nodes_state(session, OBJ_STATE_PREROLLED))
2530 break;
2532 if (SUCCEEDED(session_start_clock(session)))
2533 session->state = SESSION_STATE_STARTING_SINKS;
2534 break;
2535 case SESSION_STATE_STARTING_SINKS:
2536 if (!session_is_output_nodes_state(session, OBJ_STATE_STARTED))
2537 break;
2539 session_set_started(session);
2540 break;
2541 case SESSION_STATE_PAUSING_SINKS:
2542 if (!session_is_output_nodes_state(session, OBJ_STATE_PAUSED))
2543 break;
2545 session->state = SESSION_STATE_PAUSING_SOURCES;
2547 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2549 if (FAILED(hr = IMFMediaSource_Pause(source->source)))
2550 break;
2553 if (FAILED(hr))
2554 session_set_paused(session, hr);
2556 break;
2557 case SESSION_STATE_STOPPING_SINKS:
2558 if (!session_is_output_nodes_state(session, OBJ_STATE_STOPPED))
2559 break;
2561 session->state = SESSION_STATE_STOPPING_SOURCES;
2563 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2565 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION)
2566 IMFMediaSource_Stop(source->source);
2567 else if (FAILED(hr = IMFMediaSource_Stop(source->source)))
2568 break;
2571 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION || FAILED(hr))
2572 session_set_stopped(session, hr);
2574 break;
2575 default:
2580 static DWORD transform_node_get_stream_id(struct topo_node *node, BOOL output, DWORD index)
2582 unsigned int *map = output ? node->u.transform.output_map : node->u.transform.input_map;
2583 return map ? map[index] : index;
2586 static struct sample *transform_create_sample(IMFSample *sample)
2588 struct sample *sample_entry = heap_alloc_zero(sizeof(*sample_entry));
2590 if (sample_entry)
2592 sample_entry->sample = sample;
2593 if (sample_entry->sample)
2594 IMFSample_AddRef(sample_entry->sample);
2597 return sample_entry;
2600 static HRESULT transform_get_external_output_sample(const struct media_session *session, struct topo_node *transform,
2601 unsigned int output_index, const MFT_OUTPUT_STREAM_INFO *stream_info, IMFSample **sample)
2603 IMFTopologyNode *downstream_node;
2604 unsigned int downstream_input;
2605 IMFMediaBuffer *buffer = NULL;
2606 struct topo_node *topo_node;
2607 TOPOID node_id;
2608 HRESULT hr;
2610 if (FAILED(IMFTopologyNode_GetOutput(transform->node, output_index, &downstream_node, &downstream_input)))
2612 WARN("Failed to get connected node for output %u.\n", output_index);
2613 return MF_E_UNEXPECTED;
2616 IMFTopologyNode_GetTopoNodeID(downstream_node, &node_id);
2617 IMFTopologyNode_Release(downstream_node);
2619 topo_node = session_get_node_by_id(session, node_id);
2621 if (topo_node->type == MF_TOPOLOGY_OUTPUT_NODE && topo_node->u.sink.allocator)
2623 hr = IMFVideoSampleAllocator_AllocateSample(topo_node->u.sink.allocator, sample);
2625 else
2627 hr = MFCreateAlignedMemoryBuffer(stream_info->cbSize, stream_info->cbAlignment, &buffer);
2628 if (SUCCEEDED(hr))
2629 hr = MFCreateSample(sample);
2631 if (SUCCEEDED(hr))
2632 hr = IMFSample_AddBuffer(*sample, buffer);
2634 if (buffer)
2635 IMFMediaBuffer_Release(buffer);
2638 return hr;
2641 static HRESULT transform_node_pull_samples(const struct media_session *session, struct topo_node *node)
2643 MFT_OUTPUT_STREAM_INFO stream_info;
2644 MFT_OUTPUT_DATA_BUFFER *buffers;
2645 struct sample *queued_sample;
2646 DWORD status = 0;
2647 unsigned int i;
2648 HRESULT hr = E_UNEXPECTED;
2650 if (!(buffers = heap_calloc(node->u.transform.output_count, sizeof(*buffers))))
2651 return E_OUTOFMEMORY;
2653 for (i = 0; i < node->u.transform.output_count; ++i)
2655 buffers[i].dwStreamID = transform_node_get_stream_id(node, TRUE, i);
2656 buffers[i].pSample = NULL;
2657 buffers[i].dwStatus = 0;
2658 buffers[i].pEvents = NULL;
2660 memset(&stream_info, 0, sizeof(stream_info));
2661 if (FAILED(hr = IMFTransform_GetOutputStreamInfo(node->object.transform, buffers[i].dwStreamID, &stream_info)))
2662 break;
2664 if (!(stream_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES))
2666 if (FAILED(hr = transform_get_external_output_sample(session, node, i, &stream_info, &buffers[i].pSample)))
2667 break;
2671 if (SUCCEEDED(hr))
2672 hr = IMFTransform_ProcessOutput(node->object.transform, 0, node->u.transform.output_count, buffers, &status);
2674 /* Collect returned samples for all streams. */
2675 for (i = 0; i < node->u.transform.output_count; ++i)
2677 if (buffers[i].pEvents)
2678 IMFCollection_Release(buffers[i].pEvents);
2680 if (SUCCEEDED(hr) && !(buffers[i].dwStatus & MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE))
2682 if (session->quality_manager)
2683 IMFQualityManager_NotifyProcessOutput(session->quality_manager, node->node, i, buffers[i].pSample);
2685 queued_sample = transform_create_sample(buffers[i].pSample);
2686 list_add_tail(&node->u.transform.outputs[i].samples, &queued_sample->entry);
2689 if (buffers[i].pSample)
2690 IMFSample_Release(buffers[i].pSample);
2693 heap_free(buffers);
2695 return hr;
2698 static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input,
2699 IMFSample *sample)
2701 struct sample *sample_entry, *sample_entry2;
2702 DWORD stream_id, downstream_input;
2703 IMFTopologyNode *downstream_node;
2704 struct topo_node *topo_node;
2705 MF_TOPOLOGY_TYPE node_type;
2706 BOOL drain = FALSE;
2707 TOPOID node_id;
2708 unsigned int i;
2709 HRESULT hr;
2711 if (session->quality_manager)
2712 IMFQualityManager_NotifyProcessInput(session->quality_manager, node, input, sample);
2714 IMFTopologyNode_GetNodeType(node, &node_type);
2715 IMFTopologyNode_GetTopoNodeID(node, &node_id);
2717 topo_node = session_get_node_by_id(session, node_id);
2719 switch (node_type)
2721 case MF_TOPOLOGY_OUTPUT_NODE:
2722 if (sample)
2724 if (topo_node->u.sink.requests)
2726 if (FAILED(hr = IMFStreamSink_ProcessSample(topo_node->object.sink_stream, sample)))
2727 WARN("Stream sink failed to process sample, hr %#x.\n", hr);
2728 topo_node->u.sink.requests--;
2731 else if (FAILED(hr = IMFStreamSink_PlaceMarker(topo_node->object.sink_stream, MFSTREAMSINK_MARKER_ENDOFSEGMENT,
2732 NULL, NULL)))
2734 WARN("Failed to place sink marker, hr %#x.\n", hr);
2736 break;
2737 case MF_TOPOLOGY_TRANSFORM_NODE:
2739 transform_node_pull_samples(session, topo_node);
2741 sample_entry = transform_create_sample(sample);
2742 list_add_tail(&topo_node->u.transform.inputs[input].samples, &sample_entry->entry);
2744 for (i = 0; i < topo_node->u.transform.input_count; ++i)
2746 stream_id = transform_node_get_stream_id(topo_node, FALSE, i);
2747 LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.inputs[i].samples,
2748 struct sample, entry)
2750 if (sample_entry->sample)
2752 if ((hr = IMFTransform_ProcessInput(topo_node->object.transform, stream_id,
2753 sample_entry->sample, 0)) == MF_E_NOTACCEPTING)
2754 break;
2755 if (FAILED(hr))
2756 WARN("Failed to process input for stream %u/%u, hr %#x.\n", i, stream_id, hr);
2757 transform_release_sample(sample_entry);
2759 else
2761 transform_stream_drop_samples(&topo_node->u.transform.inputs[i]);
2762 drain = TRUE;
2767 if (drain)
2769 if (FAILED(hr = IMFTransform_ProcessMessage(topo_node->object.transform, MFT_MESSAGE_COMMAND_DRAIN, 0)))
2770 WARN("Drain command failed for transform, hr %#x.\n", hr);
2773 transform_node_pull_samples(session, topo_node);
2775 /* Remaining unprocessed input has been discarded, now queue markers for every output. */
2776 if (drain)
2778 for (i = 0; i < topo_node->u.transform.output_count; ++i)
2780 if ((sample_entry = transform_create_sample(NULL)))
2781 list_add_tail(&topo_node->u.transform.outputs[i].samples, &sample_entry->entry);
2785 /* Push down all available output. */
2786 for (i = 0; i < topo_node->u.transform.output_count; ++i)
2788 if (FAILED(IMFTopologyNode_GetOutput(node, i, &downstream_node, &downstream_input)))
2790 WARN("Failed to get connected node for output %u.\n", i);
2791 continue;
2794 LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.outputs[i].samples,
2795 struct sample, entry)
2797 if (!topo_node->u.transform.outputs[i].requests)
2798 break;
2800 session_deliver_sample_to_node(session, downstream_node, downstream_input, sample_entry->sample);
2801 topo_node->u.transform.outputs[i].requests--;
2803 transform_release_sample(sample_entry);
2806 IMFTopologyNode_Release(downstream_node);
2809 break;
2810 case MF_TOPOLOGY_TEE_NODE:
2811 FIXME("Unhandled downstream node type %d.\n", node_type);
2812 break;
2813 default:
2818 static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output)
2820 IMFTopologyNode *downstream_node, *upstream_node;
2821 unsigned int downstream_input, upstream_output;
2822 struct topo_node *topo_node;
2823 MF_TOPOLOGY_TYPE node_type;
2824 struct sample *sample;
2825 TOPOID node_id;
2826 HRESULT hr;
2828 IMFTopologyNode_GetNodeType(node, &node_type);
2829 IMFTopologyNode_GetTopoNodeID(node, &node_id);
2831 topo_node = session_get_node_by_id(session, node_id);
2833 switch (node_type)
2835 case MF_TOPOLOGY_SOURCESTREAM_NODE:
2836 if (FAILED(hr = IMFMediaStream_RequestSample(topo_node->object.source_stream, NULL)))
2837 WARN("Sample request failed, hr %#x.\n", hr);
2838 break;
2839 case MF_TOPOLOGY_TRANSFORM_NODE:
2841 if (list_empty(&topo_node->u.transform.outputs[output].samples))
2843 /* Forward request to upstream node. */
2844 if (SUCCEEDED(hr = IMFTopologyNode_GetInput(node, 0 /* FIXME */, &upstream_node, &upstream_output)))
2846 if (SUCCEEDED(hr = session_request_sample_from_node(session, upstream_node, upstream_output)))
2847 topo_node->u.transform.outputs[output].requests++;
2848 IMFTopologyNode_Release(upstream_node);
2851 else
2853 if (SUCCEEDED(hr = IMFTopologyNode_GetOutput(node, output, &downstream_node, &downstream_input)))
2855 sample = LIST_ENTRY(list_head(&topo_node->u.transform.outputs[output].samples), struct sample, entry);
2856 session_deliver_sample_to_node(session, downstream_node, downstream_input, sample->sample);
2857 transform_release_sample(sample);
2858 IMFTopologyNode_Release(downstream_node);
2862 break;
2863 case MF_TOPOLOGY_TEE_NODE:
2864 FIXME("Unhandled upstream node type %d.\n", node_type);
2865 default:
2866 hr = E_UNEXPECTED;
2869 return hr;
2872 static void session_request_sample(struct media_session *session, IMFStreamSink *sink_stream)
2874 struct topo_node *sink_node = NULL, *node;
2875 IMFTopologyNode *upstream_node;
2876 DWORD upstream_output;
2877 HRESULT hr;
2879 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2881 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink_stream)
2883 sink_node = node;
2884 break;
2888 if (!sink_node)
2889 return;
2891 if (FAILED(hr = IMFTopologyNode_GetInput(sink_node->node, 0, &upstream_node, &upstream_output)))
2893 WARN("Failed to get upstream node connection, hr %#x.\n", hr);
2894 return;
2897 if (SUCCEEDED(session_request_sample_from_node(session, upstream_node, upstream_output)))
2898 sink_node->u.sink.requests++;
2899 IMFTopologyNode_Release(upstream_node);
2902 static void session_deliver_sample(struct media_session *session, IMFMediaStream *stream, const PROPVARIANT *value)
2904 struct topo_node *source_node = NULL, *node;
2905 IMFTopologyNode *downstream_node;
2906 DWORD downstream_input;
2907 HRESULT hr;
2909 if (value && (value->vt != VT_UNKNOWN || !value->punkVal))
2911 WARN("Unexpected value type %d.\n", value->vt);
2912 return;
2915 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2917 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->object.source_stream == stream)
2919 source_node = node;
2920 break;
2924 if (!source_node)
2925 return;
2927 if (!value)
2928 source_node->flags |= TOPO_NODE_END_OF_STREAM;
2930 if (FAILED(hr = IMFTopologyNode_GetOutput(source_node->node, 0, &downstream_node, &downstream_input)))
2932 WARN("Failed to get downstream node connection, hr %#x.\n", hr);
2933 return;
2936 session_deliver_sample_to_node(session, downstream_node, downstream_input, value ? (IMFSample *)value->punkVal : NULL);
2937 IMFTopologyNode_Release(downstream_node);
2940 static void session_sink_invalidated(struct media_session *session, IMFMediaEvent *event, IMFStreamSink *sink)
2942 struct topo_node *node, *sink_node = NULL;
2943 HRESULT hr;
2945 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2947 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink)
2949 sink_node = node;
2950 break;
2954 if (!sink_node)
2955 return;
2957 if (!event)
2959 if (FAILED(hr = MFCreateMediaEvent(MESinkInvalidated, &GUID_NULL, S_OK, NULL, &event)))
2960 WARN("Failed to create event, hr %#x.\n", hr);
2963 if (!event)
2964 return;
2966 IMFMediaEvent_SetUINT64(event, &MF_EVENT_OUTPUT_NODE, sink_node->node_id);
2967 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
2969 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED);
2972 static BOOL session_nodes_is_mask_set(struct media_session *session, MF_TOPOLOGY_TYPE node_type, unsigned int flags)
2974 struct media_source *source;
2975 struct topo_node *node;
2977 if (node_type == MF_TOPOLOGY_MAX)
2979 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2981 if ((source->flags & flags) != flags)
2982 return FALSE;
2985 else
2987 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2989 if (node->type == node_type && (node->flags & flags) != flags)
2990 return FALSE;
2994 return TRUE;
2997 static void session_raise_end_of_presentation(struct media_session *session)
2999 if (!(session_nodes_is_mask_set(session, MF_TOPOLOGY_SOURCESTREAM_NODE, TOPO_NODE_END_OF_STREAM)))
3000 return;
3002 if (!(session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION))
3004 if (session_nodes_is_mask_set(session, MF_TOPOLOGY_MAX, SOURCE_FLAG_END_OF_PRESENTATION))
3006 session->presentation.flags |= SESSION_FLAG_END_OF_PRESENTATION;
3007 session_push_back_command(session, SESSION_CMD_END);
3008 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, NULL);
3013 static void session_handle_end_of_stream(struct media_session *session, IMFMediaStream *stream)
3015 struct topo_node *node;
3017 if (!(node = session_get_node_object(session, (IUnknown *)stream, MF_TOPOLOGY_SOURCESTREAM_NODE))
3018 || node->flags & TOPO_NODE_END_OF_STREAM)
3020 return;
3023 session_deliver_sample(session, stream, NULL);
3025 session_raise_end_of_presentation(session);
3028 static void session_handle_end_of_presentation(struct media_session *session, IMFMediaSource *object)
3030 struct media_source *source;
3032 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3034 if (source->source == object)
3036 if (!(source->flags & SOURCE_FLAG_END_OF_PRESENTATION))
3038 source->flags |= SOURCE_FLAG_END_OF_PRESENTATION;
3039 session_raise_end_of_presentation(session);
3042 break;
3047 static void session_sink_stream_marker(struct media_session *session, IMFStreamSink *stream_sink)
3049 struct topo_node *node;
3051 if (!(node = session_get_node_object(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE))
3052 || node->flags & TOPO_NODE_END_OF_STREAM)
3054 return;
3057 node->flags |= TOPO_NODE_END_OF_STREAM;
3059 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION &&
3060 session_nodes_is_mask_set(session, MF_TOPOLOGY_OUTPUT_NODE, TOPO_NODE_END_OF_STREAM))
3062 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED);
3063 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
3064 session_stop(session);
3068 static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
3070 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
3071 IMFMediaEventGenerator *event_source;
3072 IMFMediaEvent *event = NULL;
3073 MediaEventType event_type;
3074 IUnknown *object = NULL;
3075 IMFMediaSource *source;
3076 IMFMediaStream *stream;
3077 PROPVARIANT value;
3078 HRESULT hr;
3080 if (FAILED(hr = IMFAsyncResult_GetState(result, (IUnknown **)&event_source)))
3081 return hr;
3083 if (FAILED(hr = IMFMediaEventGenerator_EndGetEvent(event_source, result, &event)))
3085 WARN("Failed to get event from %p, hr %#x.\n", event_source, hr);
3086 goto failed;
3089 if (FAILED(hr = IMFMediaEvent_GetType(event, &event_type)))
3091 WARN("Failed to get event type, hr %#x.\n", hr);
3092 goto failed;
3095 value.vt = VT_EMPTY;
3096 if (FAILED(hr = IMFMediaEvent_GetValue(event, &value)))
3098 WARN("Failed to get event value, hr %#x.\n", hr);
3099 goto failed;
3102 switch (event_type)
3104 case MESourceStarted:
3105 case MESourcePaused:
3106 case MESourceStopped:
3107 case MEStreamStarted:
3108 case MEStreamPaused:
3109 case MEStreamStopped:
3111 EnterCriticalSection(&session->cs);
3112 session_set_source_object_state(session, (IUnknown *)event_source, event_type);
3113 LeaveCriticalSection(&session->cs);
3115 break;
3117 case MEBufferingStarted:
3118 case MEBufferingStopped:
3120 EnterCriticalSection(&session->cs);
3121 if (session_get_media_source(session, (IMFMediaSource *)event_source))
3123 if (event_type == MEBufferingStarted)
3124 IMFPresentationClock_Pause(session->clock);
3125 else
3126 IMFPresentationClock_Start(session->clock, PRESENTATION_CURRENT_POSITION);
3128 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3130 LeaveCriticalSection(&session->cs);
3131 break;
3133 case MENewStream:
3134 stream = (IMFMediaStream *)value.punkVal;
3136 if (value.vt != VT_UNKNOWN || !stream)
3138 WARN("Unexpected event value.\n");
3139 break;
3142 if (FAILED(hr = IMFMediaStream_GetMediaSource(stream, &source)))
3143 break;
3145 EnterCriticalSection(&session->cs);
3146 if (SUCCEEDED(hr = session_add_media_stream(session, source, stream)))
3147 hr = IMFMediaStream_BeginGetEvent(stream, &session->events_callback, (IUnknown *)stream);
3148 LeaveCriticalSection(&session->cs);
3150 IMFMediaSource_Release(source);
3152 break;
3153 case MEStreamSinkStarted:
3154 case MEStreamSinkPaused:
3155 case MEStreamSinkStopped:
3156 case MEStreamSinkPrerolled:
3158 EnterCriticalSection(&session->cs);
3159 session_set_sink_stream_state(session, (IMFStreamSink *)event_source, event_type);
3160 LeaveCriticalSection(&session->cs);
3162 break;
3163 case MEStreamSinkMarker:
3165 EnterCriticalSection(&session->cs);
3166 session_sink_stream_marker(session, (IMFStreamSink *)event_source);
3167 LeaveCriticalSection(&session->cs);
3169 break;
3170 case MEStreamSinkRequestSample:
3172 EnterCriticalSection(&session->cs);
3173 session_request_sample(session, (IMFStreamSink *)event_source);
3174 LeaveCriticalSection(&session->cs);
3176 break;
3177 case MEMediaSample:
3179 EnterCriticalSection(&session->cs);
3180 session_deliver_sample(session, (IMFMediaStream *)event_source, &value);
3181 LeaveCriticalSection(&session->cs);
3183 break;
3184 case MEEndOfStream:
3186 EnterCriticalSection(&session->cs);
3187 session_handle_end_of_stream(session, (IMFMediaStream *)event_source);
3188 LeaveCriticalSection(&session->cs);
3190 break;
3192 case MEEndOfPresentation:
3194 EnterCriticalSection(&session->cs);
3195 session_handle_end_of_presentation(session, (IMFMediaSource *)event_source);
3196 LeaveCriticalSection(&session->cs);
3198 break;
3199 case MEAudioSessionGroupingParamChanged:
3200 case MEAudioSessionIconChanged:
3201 case MEAudioSessionNameChanged:
3202 case MEAudioSessionVolumeChanged:
3204 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3206 break;
3207 case MEAudioSessionDeviceRemoved:
3208 case MEAudioSessionDisconnected:
3209 case MEAudioSessionExclusiveModeOverride:
3210 case MEAudioSessionFormatChanged:
3211 case MEAudioSessionServerShutdown:
3213 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3214 /* fallthrough */
3215 case MESinkInvalidated:
3217 EnterCriticalSection(&session->cs);
3218 session_sink_invalidated(session, event_type == MESinkInvalidated ? event : NULL,
3219 (IMFStreamSink *)event_source);
3220 LeaveCriticalSection(&session->cs);
3222 break;
3223 case MEQualityNotify:
3225 if (session->quality_manager)
3227 if (FAILED(IMFMediaEventGenerator_QueryInterface(event_source, &IID_IMFStreamSink, (void **)&object)))
3228 IMFMediaEventGenerator_QueryInterface(event_source, &IID_IMFTransform, (void **)&object);
3230 if (object)
3232 IMFQualityManager_NotifyQualityEvent(session->quality_manager, object, event);
3233 IUnknown_Release(object);
3237 break;
3238 default:
3242 PropVariantClear(&value);
3244 failed:
3245 if (event)
3246 IMFMediaEvent_Release(event);
3248 if (FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(event_source, iface, (IUnknown *)event_source)))
3249 WARN("Failed to re-subscribe, hr %#x.\n", hr);
3251 IMFMediaEventGenerator_Release(event_source);
3253 return hr;
3256 static const IMFAsyncCallbackVtbl session_events_callback_vtbl =
3258 session_events_callback_QueryInterface,
3259 session_events_callback_AddRef,
3260 session_events_callback_Release,
3261 session_events_callback_GetParameters,
3262 session_events_callback_Invoke,
3265 static HRESULT WINAPI session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
3267 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
3268 IsEqualIID(riid, &IID_IUnknown))
3270 *obj = iface;
3271 IMFAsyncCallback_AddRef(iface);
3272 return S_OK;
3275 WARN("Unsupported %s.\n", debugstr_guid(riid));
3276 *obj = NULL;
3277 return E_NOINTERFACE;
3280 static ULONG WINAPI session_sink_finalizer_callback_AddRef(IMFAsyncCallback *iface)
3282 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3283 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3286 static ULONG WINAPI session_sink_finalizer_callback_Release(IMFAsyncCallback *iface)
3288 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3289 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3292 static HRESULT WINAPI session_sink_finalizer_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
3294 return E_NOTIMPL;
3297 static HRESULT WINAPI session_sink_finalizer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
3299 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3300 IMFFinalizableMediaSink *fin_sink = NULL;
3301 BOOL sinks_finalized = TRUE;
3302 struct media_sink *sink;
3303 IUnknown *state;
3304 HRESULT hr;
3306 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
3307 return hr;
3309 EnterCriticalSection(&session->cs);
3311 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
3313 if (state == (IUnknown *)sink->sink)
3315 if (FAILED(hr = IMFMediaSink_QueryInterface(sink->sink, &IID_IMFFinalizableMediaSink, (void **)&fin_sink)))
3316 WARN("Unexpected, missing IMFFinalizableSink, hr %#x.\n", hr);
3318 else
3320 sinks_finalized &= sink->finalized;
3321 if (!sinks_finalized)
3322 break;
3326 IUnknown_Release(state);
3328 if (fin_sink)
3330 /* Complete session transition, or close prematurely on error. */
3331 if (SUCCEEDED(hr = IMFFinalizableMediaSink_EndFinalize(fin_sink, result)))
3333 sink->finalized = TRUE;
3334 if (sinks_finalized)
3335 session_set_closed(session, hr);
3337 IMFFinalizableMediaSink_Release(fin_sink);
3340 LeaveCriticalSection(&session->cs);
3342 return S_OK;
3345 static const IMFAsyncCallbackVtbl session_sink_finalizer_callback_vtbl =
3347 session_sink_finalizer_callback_QueryInterface,
3348 session_sink_finalizer_callback_AddRef,
3349 session_sink_finalizer_callback_Release,
3350 session_sink_finalizer_callback_GetParameters,
3351 session_sink_finalizer_callback_Invoke,
3354 static HRESULT WINAPI session_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
3356 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3357 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
3360 static ULONG WINAPI session_rate_support_AddRef(IMFRateSupport *iface)
3362 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3363 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3366 static ULONG WINAPI session_rate_support_Release(IMFRateSupport *iface)
3368 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3369 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3372 static HRESULT session_presentation_object_get_rate(IUnknown *object, MFRATE_DIRECTION direction,
3373 BOOL thin, BOOL fastest, float *result)
3375 IMFRateSupport *rate_support;
3376 float rate;
3377 HRESULT hr;
3379 /* For objects that don't support rate control, it's assumed that only forward direction is allowed, at 1.0f. */
3381 if (FAILED(hr = MFGetService(object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support)))
3383 if (direction == MFRATE_FORWARD)
3385 *result = 1.0f;
3386 return S_OK;
3388 else
3389 return MF_E_REVERSE_UNSUPPORTED;
3392 rate = 0.0f;
3393 if (fastest)
3395 if (SUCCEEDED(hr = IMFRateSupport_GetFastestRate(rate_support, direction, thin, &rate)))
3396 *result = min(fabsf(rate), *result);
3398 else
3400 if (SUCCEEDED(hr = IMFRateSupport_GetSlowestRate(rate_support, direction, thin, &rate)))
3401 *result = max(fabsf(rate), *result);
3404 IMFRateSupport_Release(rate_support);
3406 return hr;
3409 static HRESULT session_get_presentation_rate(struct media_session *session, MFRATE_DIRECTION direction,
3410 BOOL thin, BOOL fastest, float *result)
3412 struct media_source *source;
3413 struct media_sink *sink;
3414 HRESULT hr = E_POINTER;
3416 *result = 0.0f;
3418 EnterCriticalSection(&session->cs);
3420 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
3422 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3424 if (FAILED(hr = session_presentation_object_get_rate((IUnknown *)source->source, direction, thin, fastest, result)))
3425 break;
3428 if (SUCCEEDED(hr))
3430 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
3432 if (FAILED(hr = session_presentation_object_get_rate((IUnknown *)sink->sink, direction, thin, fastest, result)))
3433 break;
3438 LeaveCriticalSection(&session->cs);
3440 return hr;
3443 static HRESULT WINAPI session_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
3444 BOOL thin, float *rate)
3446 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3448 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
3450 return session_get_presentation_rate(session, direction, thin, FALSE, rate);
3453 static HRESULT WINAPI session_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
3454 BOOL thin, float *rate)
3456 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3458 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
3460 return session_get_presentation_rate(session, direction, thin, TRUE, rate);
3463 static HRESULT WINAPI session_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
3464 float *nearest_supported_rate)
3466 FIXME("%p, %d, %f, %p.\n", iface, thin, rate, nearest_supported_rate);
3468 return E_NOTIMPL;
3471 static const IMFRateSupportVtbl session_rate_support_vtbl =
3473 session_rate_support_QueryInterface,
3474 session_rate_support_AddRef,
3475 session_rate_support_Release,
3476 session_rate_support_GetSlowestRate,
3477 session_rate_support_GetFastestRate,
3478 session_rate_support_IsRateSupported,
3481 static HRESULT WINAPI session_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj)
3483 struct media_session *session = impl_session_from_IMFRateControl(iface);
3484 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
3487 static ULONG WINAPI session_rate_control_AddRef(IMFRateControl *iface)
3489 struct media_session *session = impl_session_from_IMFRateControl(iface);
3490 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3493 static ULONG WINAPI session_rate_control_Release(IMFRateControl *iface)
3495 struct media_session *session = impl_session_from_IMFRateControl(iface);
3496 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3499 static HRESULT WINAPI session_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate)
3501 FIXME("%p, %d, %f.\n", iface, thin, rate);
3503 return E_NOTIMPL;
3506 static HRESULT WINAPI session_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
3508 struct media_session *session = impl_session_from_IMFRateControl(iface);
3510 TRACE("%p, %p, %p.\n", iface, thin, rate);
3512 return IMFRateControl_GetRate(session->clock_rate_control, thin, rate);
3515 static const IMFRateControlVtbl session_rate_control_vtbl =
3517 session_rate_control_QueryInterface,
3518 session_rate_control_AddRef,
3519 session_rate_control_Release,
3520 session_rate_control_SetRate,
3521 session_rate_control_GetRate,
3524 /***********************************************************************
3525 * MFCreateMediaSession (mf.@)
3527 HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **session)
3529 BOOL without_quality_manager = FALSE;
3530 struct media_session *object;
3531 HRESULT hr;
3533 TRACE("%p, %p.\n", config, session);
3535 object = heap_alloc_zero(sizeof(*object));
3536 if (!object)
3537 return E_OUTOFMEMORY;
3539 object->IMFMediaSession_iface.lpVtbl = &mfmediasessionvtbl;
3540 object->IMFGetService_iface.lpVtbl = &session_get_service_vtbl;
3541 object->IMFRateSupport_iface.lpVtbl = &session_rate_support_vtbl;
3542 object->IMFRateControl_iface.lpVtbl = &session_rate_control_vtbl;
3543 object->commands_callback.lpVtbl = &session_commands_callback_vtbl;
3544 object->events_callback.lpVtbl = &session_events_callback_vtbl;
3545 object->sink_finalizer_callback.lpVtbl = &session_sink_finalizer_callback_vtbl;
3546 object->refcount = 1;
3547 list_init(&object->topologies);
3548 list_init(&object->commands);
3549 list_init(&object->presentation.sources);
3550 list_init(&object->presentation.sinks);
3551 list_init(&object->presentation.nodes);
3552 InitializeCriticalSection(&object->cs);
3554 if (FAILED(hr = MFCreateTopology(&object->presentation.current_topology)))
3555 goto failed;
3557 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
3558 goto failed;
3560 if (FAILED(hr = MFCreatePresentationClock(&object->clock)))
3561 goto failed;
3563 if (FAILED(hr = MFCreateSystemTimeSource(&object->system_time_source)))
3564 goto failed;
3566 if (FAILED(hr = IMFPresentationClock_QueryInterface(object->clock, &IID_IMFRateControl,
3567 (void **)&object->clock_rate_control)))
3569 goto failed;
3572 if (config)
3574 GUID clsid;
3576 if (SUCCEEDED(IMFAttributes_GetGUID(config, &MF_SESSION_TOPOLOADER, &clsid)))
3578 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTopoLoader,
3579 (void **)&object->topo_loader)))
3581 WARN("Failed to create custom topology loader, hr %#x.\n", hr);
3585 if (SUCCEEDED(IMFAttributes_GetGUID(config, &MF_SESSION_QUALITY_MANAGER, &clsid)))
3587 if (!(without_quality_manager = IsEqualGUID(&clsid, &GUID_NULL)))
3589 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFQualityManager,
3590 (void **)&object->quality_manager)))
3592 WARN("Failed to create custom quality manager, hr %#x.\n", hr);
3598 if (!object->topo_loader && FAILED(hr = MFCreateTopoLoader(&object->topo_loader)))
3599 goto failed;
3601 if (!object->quality_manager && !without_quality_manager &&
3602 FAILED(hr = MFCreateStandardQualityManager(&object->quality_manager)))
3604 goto failed;
3607 if (object->quality_manager && FAILED(hr = IMFQualityManager_NotifyPresentationClock(object->quality_manager,
3608 object->clock)))
3610 goto failed;
3613 *session = &object->IMFMediaSession_iface;
3615 return S_OK;
3617 failed:
3618 IMFMediaSession_Release(&object->IMFMediaSession_iface);
3619 return hr;
3622 static HRESULT WINAPI sink_notification_QueryInterface(IUnknown *iface, REFIID riid, void **out)
3624 if (IsEqualIID(riid, &IID_IUnknown))
3626 *out = iface;
3627 IUnknown_AddRef(iface);
3628 return S_OK;
3631 WARN("Unsupported %s.\n", debugstr_guid(riid));
3632 *out = NULL;
3633 return E_NOINTERFACE;
3636 static ULONG WINAPI sink_notification_AddRef(IUnknown *iface)
3638 struct sink_notification *notification = impl_sink_notification_from_IUnknown(iface);
3639 ULONG refcount = InterlockedIncrement(&notification->refcount);
3641 TRACE("%p, refcount %u.\n", iface, refcount);
3643 return refcount;
3646 static ULONG WINAPI sink_notification_Release(IUnknown *iface)
3648 struct sink_notification *notification = impl_sink_notification_from_IUnknown(iface);
3649 ULONG refcount = InterlockedDecrement(&notification->refcount);
3651 TRACE("%p, refcount %u.\n", iface, refcount);
3653 if (!refcount)
3655 IMFClockStateSink_Release(notification->sink);
3656 heap_free(notification);
3659 return refcount;
3662 static const IUnknownVtbl sinknotificationvtbl =
3664 sink_notification_QueryInterface,
3665 sink_notification_AddRef,
3666 sink_notification_Release,
3669 static void clock_notify_async_sink(struct presentation_clock *clock, MFTIME system_time,
3670 struct clock_state_change_param param, enum clock_notification notification, IMFClockStateSink *sink)
3672 struct sink_notification *object;
3673 IMFAsyncResult *result;
3674 HRESULT hr;
3676 object = heap_alloc(sizeof(*object));
3677 if (!object)
3678 return;
3680 object->IUnknown_iface.lpVtbl = &sinknotificationvtbl;
3681 object->refcount = 1;
3682 object->system_time = system_time;
3683 object->param = param;
3684 object->notification = notification;
3685 object->sink = sink;
3686 IMFClockStateSink_AddRef(object->sink);
3688 hr = MFCreateAsyncResult(&object->IUnknown_iface, &clock->sink_callback, NULL, &result);
3689 IUnknown_Release(&object->IUnknown_iface);
3690 if (SUCCEEDED(hr))
3692 MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD, result);
3693 IMFAsyncResult_Release(result);
3697 static HRESULT WINAPI present_clock_QueryInterface(IMFPresentationClock *iface, REFIID riid, void **out)
3699 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3701 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
3703 if (IsEqualIID(riid, &IID_IMFPresentationClock) ||
3704 IsEqualIID(riid, &IID_IMFClock) ||
3705 IsEqualIID(riid, &IID_IUnknown))
3707 *out = &clock->IMFPresentationClock_iface;
3709 else if (IsEqualIID(riid, &IID_IMFRateControl))
3711 *out = &clock->IMFRateControl_iface;
3713 else if (IsEqualIID(riid, &IID_IMFTimer))
3715 *out = &clock->IMFTimer_iface;
3717 else if (IsEqualIID(riid, &IID_IMFShutdown))
3719 *out = &clock->IMFShutdown_iface;
3721 else
3723 WARN("Unsupported %s.\n", debugstr_guid(riid));
3724 *out = NULL;
3725 return E_NOINTERFACE;
3728 IUnknown_AddRef((IUnknown *)*out);
3729 return S_OK;
3732 static ULONG WINAPI present_clock_AddRef(IMFPresentationClock *iface)
3734 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3735 ULONG refcount = InterlockedIncrement(&clock->refcount);
3737 TRACE("%p, refcount %u.\n", iface, refcount);
3739 return refcount;
3742 static ULONG WINAPI present_clock_Release(IMFPresentationClock *iface)
3744 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3745 ULONG refcount = InterlockedDecrement(&clock->refcount);
3746 struct clock_timer *timer, *timer2;
3747 struct clock_sink *sink, *sink2;
3749 TRACE("%p, refcount %u.\n", iface, refcount);
3751 if (!refcount)
3753 if (clock->time_source)
3754 IMFPresentationTimeSource_Release(clock->time_source);
3755 if (clock->time_source_sink)
3756 IMFClockStateSink_Release(clock->time_source_sink);
3757 LIST_FOR_EACH_ENTRY_SAFE(sink, sink2, &clock->sinks, struct clock_sink, entry)
3759 list_remove(&sink->entry);
3760 IMFClockStateSink_Release(sink->state_sink);
3761 heap_free(sink);
3763 LIST_FOR_EACH_ENTRY_SAFE(timer, timer2, &clock->timers, struct clock_timer, entry)
3765 list_remove(&timer->entry);
3766 IUnknown_Release(&timer->IUnknown_iface);
3768 DeleteCriticalSection(&clock->cs);
3769 heap_free(clock);
3772 return refcount;
3775 static HRESULT WINAPI present_clock_GetClockCharacteristics(IMFPresentationClock *iface, DWORD *flags)
3777 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3778 HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
3780 TRACE("%p, %p.\n", iface, flags);
3782 EnterCriticalSection(&clock->cs);
3783 if (clock->time_source)
3784 hr = IMFPresentationTimeSource_GetClockCharacteristics(clock->time_source, flags);
3785 LeaveCriticalSection(&clock->cs);
3787 return hr;
3790 static HRESULT WINAPI present_clock_GetCorrelatedTime(IMFPresentationClock *iface, DWORD reserved,
3791 LONGLONG *clock_time, MFTIME *system_time)
3793 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3794 HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
3796 TRACE("%p, %#x, %p, %p.\n", iface, reserved, clock_time, system_time);
3798 EnterCriticalSection(&clock->cs);
3799 if (clock->time_source)
3800 hr = IMFPresentationTimeSource_GetCorrelatedTime(clock->time_source, reserved, clock_time, system_time);
3801 LeaveCriticalSection(&clock->cs);
3803 return hr;
3806 static HRESULT WINAPI present_clock_GetContinuityKey(IMFPresentationClock *iface, DWORD *key)
3808 TRACE("%p, %p.\n", iface, key);
3810 *key = 0;
3812 return S_OK;
3815 static HRESULT WINAPI present_clock_GetState(IMFPresentationClock *iface, DWORD reserved, MFCLOCK_STATE *state)
3817 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3819 TRACE("%p, %#x, %p.\n", iface, reserved, state);
3821 EnterCriticalSection(&clock->cs);
3822 *state = clock->state;
3823 LeaveCriticalSection(&clock->cs);
3825 return S_OK;
3828 static HRESULT WINAPI present_clock_GetProperties(IMFPresentationClock *iface, MFCLOCK_PROPERTIES *props)
3830 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3831 HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
3833 TRACE("%p, %p.\n", iface, props);
3835 EnterCriticalSection(&clock->cs);
3836 if (clock->time_source)
3837 hr = IMFPresentationTimeSource_GetProperties(clock->time_source, props);
3838 LeaveCriticalSection(&clock->cs);
3840 return hr;
3843 static HRESULT WINAPI present_clock_SetTimeSource(IMFPresentationClock *iface,
3844 IMFPresentationTimeSource *time_source)
3846 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3847 MFCLOCK_PROPERTIES props;
3848 IMFClock *source_clock;
3849 HRESULT hr;
3851 TRACE("%p, %p.\n", iface, time_source);
3853 EnterCriticalSection(&clock->cs);
3855 if (clock->time_source)
3856 IMFPresentationTimeSource_Release(clock->time_source);
3857 if (clock->time_source_sink)
3858 IMFClockStateSink_Release(clock->time_source_sink);
3859 clock->time_source = NULL;
3860 clock->time_source_sink = NULL;
3862 hr = IMFPresentationTimeSource_QueryInterface(time_source, &IID_IMFClockStateSink, (void **)&clock->time_source_sink);
3863 if (SUCCEEDED(hr))
3865 clock->time_source = time_source;
3866 IMFPresentationTimeSource_AddRef(clock->time_source);
3869 if (SUCCEEDED(IMFPresentationTimeSource_GetUnderlyingClock(time_source, &source_clock)))
3871 if (SUCCEEDED(IMFClock_GetProperties(source_clock, &props)))
3872 clock->frequency = props.qwClockFrequency;
3873 IMFClock_Release(source_clock);
3876 if (!clock->frequency)
3877 clock->frequency = MFCLOCK_FREQUENCY_HNS;
3879 LeaveCriticalSection(&clock->cs);
3881 return hr;
3884 static HRESULT WINAPI present_clock_GetTimeSource(IMFPresentationClock *iface,
3885 IMFPresentationTimeSource **time_source)
3887 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3888 HRESULT hr = S_OK;
3890 TRACE("%p, %p.\n", iface, time_source);
3892 if (!time_source)
3893 return E_INVALIDARG;
3895 EnterCriticalSection(&clock->cs);
3896 if (clock->time_source)
3898 *time_source = clock->time_source;
3899 IMFPresentationTimeSource_AddRef(*time_source);
3901 else
3902 hr = MF_E_CLOCK_NO_TIME_SOURCE;
3903 LeaveCriticalSection(&clock->cs);
3905 return hr;
3908 static HRESULT WINAPI present_clock_GetTime(IMFPresentationClock *iface, MFTIME *time)
3910 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3911 HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
3912 MFTIME systime;
3914 TRACE("%p, %p.\n", iface, time);
3916 if (!time)
3917 return E_POINTER;
3919 EnterCriticalSection(&clock->cs);
3920 if (clock->time_source)
3921 hr = IMFPresentationTimeSource_GetCorrelatedTime(clock->time_source, 0, time, &systime);
3922 LeaveCriticalSection(&clock->cs);
3924 return hr;
3927 static HRESULT WINAPI present_clock_AddClockStateSink(IMFPresentationClock *iface, IMFClockStateSink *state_sink)
3929 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3930 struct clock_sink *sink, *cur;
3931 HRESULT hr = S_OK;
3933 TRACE("%p, %p.\n", iface, state_sink);
3935 if (!state_sink)
3936 return E_INVALIDARG;
3938 sink = heap_alloc(sizeof(*sink));
3939 if (!sink)
3940 return E_OUTOFMEMORY;
3942 sink->state_sink = state_sink;
3943 IMFClockStateSink_AddRef(sink->state_sink);
3945 EnterCriticalSection(&clock->cs);
3946 LIST_FOR_EACH_ENTRY(cur, &clock->sinks, struct clock_sink, entry)
3948 if (cur->state_sink == state_sink)
3950 hr = E_INVALIDARG;
3951 break;
3954 if (SUCCEEDED(hr))
3956 static const enum clock_notification notifications[MFCLOCK_STATE_PAUSED + 1] =
3958 /* MFCLOCK_STATE_INVALID */ 0, /* Does not apply */
3959 /* MFCLOCK_STATE_RUNNING */ CLOCK_NOTIFY_START,
3960 /* MFCLOCK_STATE_STOPPED */ CLOCK_NOTIFY_STOP,
3961 /* MFCLOCK_STATE_PAUSED */ CLOCK_NOTIFY_PAUSE,
3963 struct clock_state_change_param param;
3965 if (!clock->is_shut_down && clock->state != MFCLOCK_STATE_INVALID)
3967 param.u.offset = clock->start_offset;
3968 clock_notify_async_sink(clock, MFGetSystemTime(), param, notifications[clock->state], sink->state_sink);
3971 list_add_tail(&clock->sinks, &sink->entry);
3973 LeaveCriticalSection(&clock->cs);
3975 if (FAILED(hr))
3977 IMFClockStateSink_Release(sink->state_sink);
3978 heap_free(sink);
3981 return hr;
3984 static HRESULT WINAPI present_clock_RemoveClockStateSink(IMFPresentationClock *iface,
3985 IMFClockStateSink *state_sink)
3987 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
3988 struct clock_sink *sink;
3990 TRACE("%p, %p.\n", iface, state_sink);
3992 if (!state_sink)
3993 return E_INVALIDARG;
3995 EnterCriticalSection(&clock->cs);
3996 LIST_FOR_EACH_ENTRY(sink, &clock->sinks, struct clock_sink, entry)
3998 if (sink->state_sink == state_sink)
4000 IMFClockStateSink_Release(sink->state_sink);
4001 list_remove(&sink->entry);
4002 heap_free(sink);
4003 break;
4006 LeaveCriticalSection(&clock->cs);
4008 return S_OK;
4011 static HRESULT clock_call_state_change(MFTIME system_time, struct clock_state_change_param param,
4012 enum clock_notification notification, IMFClockStateSink *sink)
4014 HRESULT hr = S_OK;
4016 switch (notification)
4018 case CLOCK_NOTIFY_START:
4019 hr = IMFClockStateSink_OnClockStart(sink, system_time, param.u.offset);
4020 break;
4021 case CLOCK_NOTIFY_STOP:
4022 hr = IMFClockStateSink_OnClockStop(sink, system_time);
4023 break;
4024 case CLOCK_NOTIFY_PAUSE:
4025 hr = IMFClockStateSink_OnClockPause(sink, system_time);
4026 break;
4027 case CLOCK_NOTIFY_RESTART:
4028 hr = IMFClockStateSink_OnClockRestart(sink, system_time);
4029 break;
4030 case CLOCK_NOTIFY_SET_RATE:
4031 /* System time source does not allow 0.0 rate, presentation clock allows it without raising errors. */
4032 IMFClockStateSink_OnClockSetRate(sink, system_time, param.u.rate);
4033 break;
4034 default:
4038 return hr;
4041 static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_command command,
4042 struct clock_state_change_param param)
4044 static const BYTE state_change_is_allowed[MFCLOCK_STATE_PAUSED+1][CLOCK_CMD_MAX] =
4045 { /* S S* P, R */
4046 /* INVALID */ { 1, 1, 1, 1 },
4047 /* RUNNING */ { 1, 1, 1, 1 },
4048 /* STOPPED */ { 1, 1, 0, 1 },
4049 /* PAUSED */ { 1, 1, 0, 1 },
4051 static const MFCLOCK_STATE states[CLOCK_CMD_MAX] =
4053 /* CLOCK_CMD_START */ MFCLOCK_STATE_RUNNING,
4054 /* CLOCK_CMD_STOP */ MFCLOCK_STATE_STOPPED,
4055 /* CLOCK_CMD_PAUSE */ MFCLOCK_STATE_PAUSED,
4056 /* CLOCK_CMD_SET_RATE */ 0, /* Unused */
4058 static const enum clock_notification notifications[CLOCK_CMD_MAX] =
4060 /* CLOCK_CMD_START */ CLOCK_NOTIFY_START,
4061 /* CLOCK_CMD_STOP */ CLOCK_NOTIFY_STOP,
4062 /* CLOCK_CMD_PAUSE */ CLOCK_NOTIFY_PAUSE,
4063 /* CLOCK_CMD_SET_RATE */ CLOCK_NOTIFY_SET_RATE,
4065 enum clock_notification notification;
4066 struct clock_sink *sink;
4067 MFCLOCK_STATE old_state;
4068 IMFAsyncResult *result;
4069 MFTIME system_time;
4070 HRESULT hr;
4072 if (!clock->time_source)
4073 return MF_E_CLOCK_NO_TIME_SOURCE;
4075 if (command != CLOCK_CMD_SET_RATE && clock->state == states[command] && clock->state != MFCLOCK_STATE_RUNNING)
4076 return MF_E_CLOCK_STATE_ALREADY_SET;
4078 if (!state_change_is_allowed[clock->state][command])
4079 return MF_E_INVALIDREQUEST;
4081 system_time = MFGetSystemTime();
4083 if (command == CLOCK_CMD_START && clock->state == MFCLOCK_STATE_PAUSED &&
4084 param.u.offset == PRESENTATION_CURRENT_POSITION)
4086 notification = CLOCK_NOTIFY_RESTART;
4088 else
4089 notification = notifications[command];
4091 if (FAILED(hr = clock_call_state_change(system_time, param, notification, clock->time_source_sink)))
4092 return hr;
4094 old_state = clock->state;
4095 if (command != CLOCK_CMD_SET_RATE)
4096 clock->state = states[command];
4098 /* Dump all pending timer requests immediately on start; otherwise try to cancel scheduled items when
4099 transitioning from running state. */
4100 if ((clock->state == MFCLOCK_STATE_RUNNING) ^ (old_state == MFCLOCK_STATE_RUNNING))
4102 struct clock_timer *timer, *timer2;
4104 if (clock->state == MFCLOCK_STATE_RUNNING)
4106 LIST_FOR_EACH_ENTRY_SAFE(timer, timer2, &clock->timers, struct clock_timer, entry)
4108 list_remove(&timer->entry);
4109 hr = MFCreateAsyncResult(&timer->IUnknown_iface, &clock->timer_callback, NULL, &result);
4110 IUnknown_Release(&timer->IUnknown_iface);
4111 if (SUCCEEDED(hr))
4113 MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_TIMER, result);
4114 IMFAsyncResult_Release(result);
4118 else
4120 LIST_FOR_EACH_ENTRY(timer, &clock->timers, struct clock_timer, entry)
4122 if (timer->key)
4124 MFCancelWorkItem(timer->key);
4125 timer->key = 0;
4131 LIST_FOR_EACH_ENTRY(sink, &clock->sinks, struct clock_sink, entry)
4133 clock_notify_async_sink(clock, system_time, param, notification, sink->state_sink);
4136 return S_OK;
4139 static HRESULT WINAPI present_clock_Start(IMFPresentationClock *iface, LONGLONG start_offset)
4141 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
4142 struct clock_state_change_param param = {{0}};
4143 HRESULT hr;
4145 TRACE("%p, %s.\n", iface, debugstr_time(start_offset));
4147 EnterCriticalSection(&clock->cs);
4148 clock->start_offset = param.u.offset = start_offset;
4149 hr = clock_change_state(clock, CLOCK_CMD_START, param);
4150 LeaveCriticalSection(&clock->cs);
4152 return hr;
4155 static HRESULT WINAPI present_clock_Stop(IMFPresentationClock *iface)
4157 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
4158 struct clock_state_change_param param = {{0}};
4159 HRESULT hr;
4161 TRACE("%p.\n", iface);
4163 EnterCriticalSection(&clock->cs);
4164 hr = clock_change_state(clock, CLOCK_CMD_STOP, param);
4165 LeaveCriticalSection(&clock->cs);
4167 return hr;
4170 static HRESULT WINAPI present_clock_Pause(IMFPresentationClock *iface)
4172 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
4173 struct clock_state_change_param param = {{0}};
4174 HRESULT hr;
4176 TRACE("%p.\n", iface);
4178 EnterCriticalSection(&clock->cs);
4179 hr = clock_change_state(clock, CLOCK_CMD_PAUSE, param);
4180 LeaveCriticalSection(&clock->cs);
4182 return hr;
4185 static const IMFPresentationClockVtbl presentationclockvtbl =
4187 present_clock_QueryInterface,
4188 present_clock_AddRef,
4189 present_clock_Release,
4190 present_clock_GetClockCharacteristics,
4191 present_clock_GetCorrelatedTime,
4192 present_clock_GetContinuityKey,
4193 present_clock_GetState,
4194 present_clock_GetProperties,
4195 present_clock_SetTimeSource,
4196 present_clock_GetTimeSource,
4197 present_clock_GetTime,
4198 present_clock_AddClockStateSink,
4199 present_clock_RemoveClockStateSink,
4200 present_clock_Start,
4201 present_clock_Stop,
4202 present_clock_Pause,
4205 static HRESULT WINAPI present_clock_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **out)
4207 struct presentation_clock *clock = impl_from_IMFRateControl(iface);
4208 return IMFPresentationClock_QueryInterface(&clock->IMFPresentationClock_iface, riid, out);
4211 static ULONG WINAPI present_clock_rate_control_AddRef(IMFRateControl *iface)
4213 struct presentation_clock *clock = impl_from_IMFRateControl(iface);
4214 return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
4217 static ULONG WINAPI present_clock_rate_control_Release(IMFRateControl *iface)
4219 struct presentation_clock *clock = impl_from_IMFRateControl(iface);
4220 return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
4223 static HRESULT WINAPI present_clock_rate_SetRate(IMFRateControl *iface, BOOL thin, float rate)
4225 struct presentation_clock *clock = impl_from_IMFRateControl(iface);
4226 struct clock_state_change_param param;
4227 HRESULT hr;
4229 TRACE("%p, %d, %f.\n", iface, thin, rate);
4231 if (thin)
4232 return MF_E_THINNING_UNSUPPORTED;
4234 EnterCriticalSection(&clock->cs);
4235 param.u.rate = rate;
4236 if (SUCCEEDED(hr = clock_change_state(clock, CLOCK_CMD_SET_RATE, param)))
4237 clock->rate = rate;
4238 LeaveCriticalSection(&clock->cs);
4240 return hr;
4243 static HRESULT WINAPI present_clock_rate_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
4245 struct presentation_clock *clock = impl_from_IMFRateControl(iface);
4247 TRACE("%p, %p, %p.\n", iface, thin, rate);
4249 if (!rate)
4250 return E_INVALIDARG;
4252 if (thin)
4253 *thin = FALSE;
4255 EnterCriticalSection(&clock->cs);
4256 *rate = clock->rate;
4257 LeaveCriticalSection(&clock->cs);
4259 return S_OK;
4262 static const IMFRateControlVtbl presentclockratecontrolvtbl =
4264 present_clock_rate_control_QueryInterface,
4265 present_clock_rate_control_AddRef,
4266 present_clock_rate_control_Release,
4267 present_clock_rate_SetRate,
4268 present_clock_rate_GetRate,
4271 static HRESULT WINAPI present_clock_timer_QueryInterface(IMFTimer *iface, REFIID riid, void **out)
4273 struct presentation_clock *clock = impl_from_IMFTimer(iface);
4274 return IMFPresentationClock_QueryInterface(&clock->IMFPresentationClock_iface, riid, out);
4277 static ULONG WINAPI present_clock_timer_AddRef(IMFTimer *iface)
4279 struct presentation_clock *clock = impl_from_IMFTimer(iface);
4280 return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
4283 static ULONG WINAPI present_clock_timer_Release(IMFTimer *iface)
4285 struct presentation_clock *clock = impl_from_IMFTimer(iface);
4286 return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
4289 static HRESULT present_clock_schedule_timer(struct presentation_clock *clock, DWORD flags, LONGLONG time,
4290 struct clock_timer *timer)
4292 IMFAsyncResult *result;
4293 MFTIME systime, clocktime;
4294 LONGLONG frequency;
4295 HRESULT hr;
4297 if (!(flags & MFTIMER_RELATIVE))
4299 if (FAILED(hr = IMFPresentationTimeSource_GetCorrelatedTime(clock->time_source, 0, &clocktime, &systime)))
4301 WARN("Failed to get clock time, hr %#x.\n", hr);
4302 return hr;
4304 time -= clocktime;
4307 frequency = clock->frequency / 1000;
4308 time /= frequency;
4310 /* Scheduled item is using clock instance callback, with timer instance as an object. Clock callback will
4311 call user callback and cleanup timer list. */
4313 if (FAILED(hr = MFCreateAsyncResult(&timer->IUnknown_iface, &clock->timer_callback, NULL, &result)))
4314 return hr;
4316 hr = MFScheduleWorkItemEx(result, -time, &timer->key);
4317 IMFAsyncResult_Release(result);
4319 return hr;
4322 static HRESULT WINAPI clock_timer_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
4324 if (IsEqualIID(riid, &IID_IUnknown))
4326 *obj = iface;
4327 IUnknown_AddRef(iface);
4328 return S_OK;
4331 *obj = NULL;
4332 return E_NOINTERFACE;
4335 static ULONG WINAPI clock_timer_AddRef(IUnknown *iface)
4337 struct clock_timer *timer = impl_clock_timer_from_IUnknown(iface);
4338 return InterlockedIncrement(&timer->refcount);
4341 static ULONG WINAPI clock_timer_Release(IUnknown *iface)
4343 struct clock_timer *timer = impl_clock_timer_from_IUnknown(iface);
4344 ULONG refcount = InterlockedDecrement(&timer->refcount);
4346 if (!refcount)
4348 IMFAsyncResult_Release(timer->result);
4349 IMFAsyncCallback_Release(timer->callback);
4350 heap_free(timer);
4353 return refcount;
4356 static const IUnknownVtbl clock_timer_vtbl =
4358 clock_timer_QueryInterface,
4359 clock_timer_AddRef,
4360 clock_timer_Release,
4363 static HRESULT WINAPI present_clock_timer_SetTimer(IMFTimer *iface, DWORD flags, LONGLONG time,
4364 IMFAsyncCallback *callback, IUnknown *state, IUnknown **cancel_key)
4366 struct presentation_clock *clock = impl_from_IMFTimer(iface);
4367 struct clock_timer *clock_timer;
4368 HRESULT hr;
4370 TRACE("%p, %#x, %s, %p, %p, %p.\n", iface, flags, debugstr_time(time), callback, state, cancel_key);
4372 if (!(clock_timer = heap_alloc_zero(sizeof(*clock_timer))))
4373 return E_OUTOFMEMORY;
4375 if (FAILED(hr = MFCreateAsyncResult(NULL, NULL, state, &clock_timer->result)))
4377 heap_free(clock_timer);
4378 return hr;
4381 clock_timer->IUnknown_iface.lpVtbl = &clock_timer_vtbl;
4382 clock_timer->refcount = 1;
4383 clock_timer->callback = callback;
4384 IMFAsyncCallback_AddRef(clock_timer->callback);
4386 EnterCriticalSection(&clock->cs);
4388 if (clock->state == MFCLOCK_STATE_RUNNING)
4389 hr = present_clock_schedule_timer(clock, flags, time, clock_timer);
4390 else if (clock->state == MFCLOCK_STATE_STOPPED)
4391 hr = MF_S_CLOCK_STOPPED;
4393 if (SUCCEEDED(hr))
4395 list_add_tail(&clock->timers, &clock_timer->entry);
4396 if (cancel_key)
4398 *cancel_key = &clock_timer->IUnknown_iface;
4399 IUnknown_AddRef(*cancel_key);
4403 LeaveCriticalSection(&clock->cs);
4405 if (FAILED(hr))
4406 IUnknown_Release(&clock_timer->IUnknown_iface);
4408 return hr;
4411 static HRESULT WINAPI present_clock_timer_CancelTimer(IMFTimer *iface, IUnknown *cancel_key)
4413 struct presentation_clock *clock = impl_from_IMFTimer(iface);
4414 struct clock_timer *timer;
4416 TRACE("%p, %p.\n", iface, cancel_key);
4418 EnterCriticalSection(&clock->cs);
4420 LIST_FOR_EACH_ENTRY(timer, &clock->timers, struct clock_timer, entry)
4422 if (&timer->IUnknown_iface == cancel_key)
4424 list_remove(&timer->entry);
4425 if (timer->key)
4427 MFCancelWorkItem(timer->key);
4428 timer->key = 0;
4430 IUnknown_Release(&timer->IUnknown_iface);
4431 break;
4435 LeaveCriticalSection(&clock->cs);
4437 return S_OK;
4440 static const IMFTimerVtbl presentclocktimervtbl =
4442 present_clock_timer_QueryInterface,
4443 present_clock_timer_AddRef,
4444 present_clock_timer_Release,
4445 present_clock_timer_SetTimer,
4446 present_clock_timer_CancelTimer,
4449 static HRESULT WINAPI present_clock_shutdown_QueryInterface(IMFShutdown *iface, REFIID riid, void **out)
4451 struct presentation_clock *clock = impl_from_IMFShutdown(iface);
4452 return IMFPresentationClock_QueryInterface(&clock->IMFPresentationClock_iface, riid, out);
4455 static ULONG WINAPI present_clock_shutdown_AddRef(IMFShutdown *iface)
4457 struct presentation_clock *clock = impl_from_IMFShutdown(iface);
4458 return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
4461 static ULONG WINAPI present_clock_shutdown_Release(IMFShutdown *iface)
4463 struct presentation_clock *clock = impl_from_IMFShutdown(iface);
4464 return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
4467 static HRESULT WINAPI present_clock_shutdown_Shutdown(IMFShutdown *iface)
4469 struct presentation_clock *clock = impl_from_IMFShutdown(iface);
4471 TRACE("%p.\n", iface);
4473 EnterCriticalSection(&clock->cs);
4474 clock->is_shut_down = TRUE;
4475 LeaveCriticalSection(&clock->cs);
4477 return S_OK;
4480 static HRESULT WINAPI present_clock_shutdown_GetShutdownStatus(IMFShutdown *iface, MFSHUTDOWN_STATUS *status)
4482 struct presentation_clock *clock = impl_from_IMFShutdown(iface);
4483 HRESULT hr = S_OK;
4485 TRACE("%p, %p.\n", iface, status);
4487 if (!status)
4488 return E_INVALIDARG;
4490 EnterCriticalSection(&clock->cs);
4491 if (clock->is_shut_down)
4492 *status = MFSHUTDOWN_COMPLETED;
4493 else
4494 hr = MF_E_INVALIDREQUEST;
4495 LeaveCriticalSection(&clock->cs);
4497 return hr;
4500 static const IMFShutdownVtbl presentclockshutdownvtbl =
4502 present_clock_shutdown_QueryInterface,
4503 present_clock_shutdown_AddRef,
4504 present_clock_shutdown_Release,
4505 present_clock_shutdown_Shutdown,
4506 present_clock_shutdown_GetShutdownStatus,
4509 static HRESULT WINAPI present_clock_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **out)
4511 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
4512 IsEqualIID(riid, &IID_IUnknown))
4514 *out = iface;
4515 IMFAsyncCallback_AddRef(iface);
4516 return S_OK;
4519 WARN("Unsupported %s.\n", wine_dbgstr_guid(riid));
4520 *out = NULL;
4521 return E_NOINTERFACE;
4524 static ULONG WINAPI present_clock_sink_callback_AddRef(IMFAsyncCallback *iface)
4526 struct presentation_clock *clock = impl_from_sink_callback_IMFAsyncCallback(iface);
4527 return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
4530 static ULONG WINAPI present_clock_sink_callback_Release(IMFAsyncCallback *iface)
4532 struct presentation_clock *clock = impl_from_sink_callback_IMFAsyncCallback(iface);
4533 return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
4536 static HRESULT WINAPI present_clock_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
4538 return E_NOTIMPL;
4541 static HRESULT WINAPI present_clock_sink_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
4543 struct sink_notification *data;
4544 IUnknown *object;
4545 HRESULT hr;
4547 if (FAILED(hr = IMFAsyncResult_GetObject(result, &object)))
4548 return hr;
4550 data = impl_sink_notification_from_IUnknown(object);
4552 clock_call_state_change(data->system_time, data->param, data->notification, data->sink);
4554 IUnknown_Release(object);
4556 return S_OK;
4559 static const IMFAsyncCallbackVtbl presentclocksinkcallbackvtbl =
4561 present_clock_callback_QueryInterface,
4562 present_clock_sink_callback_AddRef,
4563 present_clock_sink_callback_Release,
4564 present_clock_callback_GetParameters,
4565 present_clock_sink_callback_Invoke,
4568 static ULONG WINAPI present_clock_timer_callback_AddRef(IMFAsyncCallback *iface)
4570 struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface);
4571 return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
4574 static ULONG WINAPI present_clock_timer_callback_Release(IMFAsyncCallback *iface)
4576 struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface);
4577 return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
4580 static HRESULT WINAPI present_clock_timer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
4582 struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface);
4583 struct clock_timer *timer;
4584 IUnknown *object;
4585 HRESULT hr;
4587 if (FAILED(hr = IMFAsyncResult_GetObject(result, &object)))
4588 return hr;
4590 timer = impl_clock_timer_from_IUnknown(object);
4592 EnterCriticalSection(&clock->cs);
4593 list_remove(&timer->entry);
4594 IUnknown_Release(&timer->IUnknown_iface);
4595 LeaveCriticalSection(&clock->cs);
4597 IMFAsyncCallback_Invoke(timer->callback, timer->result);
4599 IUnknown_Release(object);
4601 return S_OK;
4604 static const IMFAsyncCallbackVtbl presentclocktimercallbackvtbl =
4606 present_clock_callback_QueryInterface,
4607 present_clock_timer_callback_AddRef,
4608 present_clock_timer_callback_Release,
4609 present_clock_callback_GetParameters,
4610 present_clock_timer_callback_Invoke,
4613 /***********************************************************************
4614 * MFCreatePresentationClock (mf.@)
4616 HRESULT WINAPI MFCreatePresentationClock(IMFPresentationClock **clock)
4618 struct presentation_clock *object;
4620 TRACE("%p.\n", clock);
4622 object = heap_alloc_zero(sizeof(*object));
4623 if (!object)
4624 return E_OUTOFMEMORY;
4626 object->IMFPresentationClock_iface.lpVtbl = &presentationclockvtbl;
4627 object->IMFRateControl_iface.lpVtbl = &presentclockratecontrolvtbl;
4628 object->IMFTimer_iface.lpVtbl = &presentclocktimervtbl;
4629 object->IMFShutdown_iface.lpVtbl = &presentclockshutdownvtbl;
4630 object->sink_callback.lpVtbl = &presentclocksinkcallbackvtbl;
4631 object->timer_callback.lpVtbl = &presentclocktimercallbackvtbl;
4632 object->refcount = 1;
4633 list_init(&object->sinks);
4634 list_init(&object->timers);
4635 object->rate = 1.0f;
4636 InitializeCriticalSection(&object->cs);
4638 *clock = &object->IMFPresentationClock_iface;
4640 return S_OK;
4643 static HRESULT WINAPI standard_quality_manager_QueryInterface(IMFQualityManager *iface, REFIID riid, void **out)
4645 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
4647 if (IsEqualIID(riid, &IID_IMFQualityManager) ||
4648 IsEqualIID(riid, &IID_IUnknown))
4650 *out = iface;
4651 IMFQualityManager_AddRef(iface);
4652 return S_OK;
4655 WARN("Unsupported %s.\n", debugstr_guid(riid));
4656 *out = NULL;
4657 return E_NOINTERFACE;
4660 static ULONG WINAPI standard_quality_manager_AddRef(IMFQualityManager *iface)
4662 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
4663 ULONG refcount = InterlockedIncrement(&manager->refcount);
4665 TRACE("%p, refcount %u.\n", iface, refcount);
4667 return refcount;
4670 static ULONG WINAPI standard_quality_manager_Release(IMFQualityManager *iface)
4672 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
4673 ULONG refcount = InterlockedDecrement(&manager->refcount);
4675 TRACE("%p, refcount %u.\n", iface, refcount);
4677 if (!refcount)
4679 if (manager->clock)
4680 IMFPresentationClock_Release(manager->clock);
4681 DeleteCriticalSection(&manager->cs);
4682 heap_free(manager);
4685 return refcount;
4688 static HRESULT WINAPI standard_quality_manager_NotifyTopology(IMFQualityManager *iface, IMFTopology *topology)
4690 FIXME("%p, %p stub.\n", iface, topology);
4692 return S_OK;
4695 static HRESULT WINAPI standard_quality_manager_NotifyPresentationClock(IMFQualityManager *iface,
4696 IMFPresentationClock *clock)
4698 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
4700 TRACE("%p, %p.\n", iface, clock);
4702 if (!clock)
4703 return E_POINTER;
4705 EnterCriticalSection(&manager->cs);
4706 if (manager->clock)
4707 IMFPresentationClock_Release(manager->clock);
4708 manager->clock = clock;
4709 IMFPresentationClock_AddRef(manager->clock);
4710 LeaveCriticalSection(&manager->cs);
4712 return S_OK;
4715 static HRESULT WINAPI standard_quality_manager_NotifyProcessInput(IMFQualityManager *iface, IMFTopologyNode *node,
4716 LONG input_index, IMFSample *sample)
4718 TRACE("%p, %p, %d, %p stub.\n", iface, node, input_index, sample);
4720 return E_NOTIMPL;
4723 static HRESULT WINAPI standard_quality_manager_NotifyProcessOutput(IMFQualityManager *iface, IMFTopologyNode *node,
4724 LONG output_index, IMFSample *sample)
4726 TRACE("%p, %p, %d, %p stub.\n", iface, node, output_index, sample);
4728 return E_NOTIMPL;
4731 static HRESULT WINAPI standard_quality_manager_NotifyQualityEvent(IMFQualityManager *iface, IUnknown *object,
4732 IMFMediaEvent *event)
4734 FIXME("%p, %p, %p stub.\n", iface, object, event);
4736 return E_NOTIMPL;
4739 static HRESULT WINAPI standard_quality_manager_Shutdown(IMFQualityManager *iface)
4741 FIXME("%p stub.\n", iface);
4743 return E_NOTIMPL;
4746 static IMFQualityManagerVtbl standard_quality_manager_vtbl =
4748 standard_quality_manager_QueryInterface,
4749 standard_quality_manager_AddRef,
4750 standard_quality_manager_Release,
4751 standard_quality_manager_NotifyTopology,
4752 standard_quality_manager_NotifyPresentationClock,
4753 standard_quality_manager_NotifyProcessInput,
4754 standard_quality_manager_NotifyProcessOutput,
4755 standard_quality_manager_NotifyQualityEvent,
4756 standard_quality_manager_Shutdown,
4759 HRESULT WINAPI MFCreateStandardQualityManager(IMFQualityManager **manager)
4761 struct quality_manager *object;
4763 TRACE("%p.\n", manager);
4765 object = heap_alloc_zero(sizeof(*object));
4766 if (!object)
4767 return E_OUTOFMEMORY;
4769 object->IMFQualityManager_iface.lpVtbl = &standard_quality_manager_vtbl;
4770 object->refcount = 1;
4771 InitializeCriticalSection(&object->cs);
4773 *manager = &object->IMFQualityManager_iface;
4775 return S_OK;