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