mf: Move presentation clock implementation to a separate file.
[wine.git] / dlls / mf / session.c
bloba7f81e694c20d635c8b5961bff6e7bc3e88fb6c1
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>
21 #include <float.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "mfidl.h"
28 #include "evr.h"
30 #include "wine/debug.h"
31 #include "wine/heap.h"
32 #include "wine/list.h"
34 #include "mf_private.h"
36 #include "initguid.h"
38 DEFINE_GUID(_MF_TOPONODE_IMFActivate, 0x33706f4a, 0x309a, 0x49be, 0xa8, 0xdd, 0xe7, 0xc0, 0x87, 0x5e, 0xb6, 0x79);
40 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
42 enum session_command
44 SESSION_CMD_CLEAR_TOPOLOGIES,
45 SESSION_CMD_CLOSE,
46 SESSION_CMD_SET_TOPOLOGY,
47 SESSION_CMD_START,
48 SESSION_CMD_PAUSE,
49 SESSION_CMD_STOP,
50 /* Internally used commands. */
51 SESSION_CMD_END,
52 SESSION_CMD_QM_NOTIFY_TOPOLOGY,
53 SESSION_CMD_SA_READY,
56 struct session_op
58 IUnknown IUnknown_iface;
59 LONG refcount;
60 enum session_command command;
61 union
63 struct
65 DWORD flags;
66 IMFTopology *topology;
67 } set_topology;
68 struct
70 GUID time_format;
71 PROPVARIANT start_position;
72 } start;
73 struct
75 IMFTopology *topology;
76 } notify_topology;
77 struct
79 TOPOID node_id;
80 } sa_ready;
81 } u;
82 struct list entry;
85 struct queued_topology
87 struct list entry;
88 IMFTopology *topology;
89 MF_TOPOSTATUS status;
92 enum session_state
94 SESSION_STATE_STOPPED = 0,
95 SESSION_STATE_STARTING_SOURCES,
96 SESSION_STATE_PREROLLING_SINKS,
97 SESSION_STATE_STARTING_SINKS,
98 SESSION_STATE_STARTED,
99 SESSION_STATE_PAUSING_SINKS,
100 SESSION_STATE_PAUSING_SOURCES,
101 SESSION_STATE_PAUSED,
102 SESSION_STATE_STOPPING_SINKS,
103 SESSION_STATE_STOPPING_SOURCES,
104 SESSION_STATE_FINALIZING_SINKS,
105 SESSION_STATE_CLOSED,
106 SESSION_STATE_SHUT_DOWN,
109 enum object_state
111 OBJ_STATE_STOPPED = 0,
112 OBJ_STATE_STARTED,
113 OBJ_STATE_PAUSED,
114 OBJ_STATE_PREROLLED,
115 OBJ_STATE_INVALID,
118 enum media_source_flags
120 SOURCE_FLAG_END_OF_PRESENTATION = 0x1,
123 struct media_source
125 struct list entry;
126 IMFMediaSource *source;
127 IMFPresentationDescriptor *pd;
128 enum object_state state;
129 unsigned int flags;
132 struct media_sink
134 struct list entry;
135 IMFMediaSink *sink;
136 IMFMediaSinkPreroll *preroll;
137 IMFMediaEventGenerator *event_generator;
138 BOOL finalized;
141 struct sample
143 struct list entry;
144 IMFSample *sample;
147 struct transform_stream
149 struct list samples;
150 unsigned int requests;
151 unsigned int min_buffer_size;
154 enum topo_node_flags
156 TOPO_NODE_END_OF_STREAM = 0x1,
159 struct topo_node
161 struct list entry;
162 struct media_session *session;
163 MF_TOPOLOGY_TYPE type;
164 TOPOID node_id;
165 IMFTopologyNode *node;
166 enum object_state state;
167 unsigned int flags;
168 union
170 IMFMediaStream *source_stream;
171 IMFStreamSink *sink_stream;
172 IMFTransform *transform;
173 IUnknown *object;
174 } object;
176 union
178 struct
180 IMFMediaSource *source;
181 unsigned int stream_id;
182 } source;
183 struct
185 unsigned int requests;
186 IMFVideoSampleAllocatorNotify notify_cb;
187 IMFVideoSampleAllocator *allocator;
188 IMFVideoSampleAllocatorCallback *allocator_cb;
189 } sink;
190 struct
192 struct transform_stream *inputs;
193 unsigned int *input_map;
194 unsigned int input_count;
196 struct transform_stream *outputs;
197 unsigned int *output_map;
198 unsigned int output_count;
199 } transform;
200 } u;
203 enum presentation_flags
205 SESSION_FLAG_SOURCES_SUBSCRIBED = 0x1,
206 SESSION_FLAG_PRESENTATION_CLOCK_SET = 0x2,
207 SESSION_FLAG_FINALIZE_SINKS = 0x4,
208 SESSION_FLAG_NEEDS_PREROLL = 0x8,
209 SESSION_FLAG_END_OF_PRESENTATION = 0x10,
212 struct media_session
214 IMFMediaSession IMFMediaSession_iface;
215 IMFGetService IMFGetService_iface;
216 IMFRateSupport IMFRateSupport_iface;
217 IMFRateControl IMFRateControl_iface;
218 IMFTopologyNodeAttributeEditor IMFTopologyNodeAttributeEditor_iface;
219 IMFAsyncCallback commands_callback;
220 IMFAsyncCallback events_callback;
221 IMFAsyncCallback sink_finalizer_callback;
222 LONG refcount;
223 IMFMediaEventQueue *event_queue;
224 IMFPresentationClock *clock;
225 IMFPresentationTimeSource *system_time_source;
226 IMFRateControl *clock_rate_control;
227 IMFTopoLoader *topo_loader;
228 IMFQualityManager *quality_manager;
229 struct
231 IMFTopology *current_topology;
232 MF_TOPOSTATUS topo_status;
233 MFTIME clock_stop_time;
234 unsigned int flags;
235 struct list sources;
236 struct list sinks;
237 struct list nodes;
239 /* Latest Start() arguments. */
240 GUID time_format;
241 PROPVARIANT start_position;
242 } presentation;
243 struct list topologies;
244 struct list commands;
245 enum session_state state;
246 DWORD caps;
247 CRITICAL_SECTION cs;
250 enum quality_manager_state
252 QUALITY_MANAGER_READY = 0,
253 QUALITY_MANAGER_SHUT_DOWN,
256 struct quality_manager
258 IMFQualityManager IMFQualityManager_iface;
259 IMFClockStateSink IMFClockStateSink_iface;
260 LONG refcount;
262 IMFTopology *topology;
263 IMFPresentationClock *clock;
264 unsigned int state;
265 CRITICAL_SECTION cs;
268 static inline struct media_session *impl_from_IMFMediaSession(IMFMediaSession *iface)
270 return CONTAINING_RECORD(iface, struct media_session, IMFMediaSession_iface);
273 static struct media_session *impl_from_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
275 return CONTAINING_RECORD(iface, struct media_session, commands_callback);
278 static struct media_session *impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
280 return CONTAINING_RECORD(iface, struct media_session, events_callback);
283 static struct media_session *impl_from_sink_finalizer_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
285 return CONTAINING_RECORD(iface, struct media_session, sink_finalizer_callback);
288 static struct media_session *impl_from_IMFGetService(IMFGetService *iface)
290 return CONTAINING_RECORD(iface, struct media_session, IMFGetService_iface);
293 static struct media_session *impl_session_from_IMFRateSupport(IMFRateSupport *iface)
295 return CONTAINING_RECORD(iface, struct media_session, IMFRateSupport_iface);
298 static struct media_session *impl_session_from_IMFRateControl(IMFRateControl *iface)
300 return CONTAINING_RECORD(iface, struct media_session, IMFRateControl_iface);
303 static struct media_session *impl_session_from_IMFTopologyNodeAttributeEditor(IMFTopologyNodeAttributeEditor *iface)
305 return CONTAINING_RECORD(iface, struct media_session, IMFTopologyNodeAttributeEditor_iface);
308 static struct session_op *impl_op_from_IUnknown(IUnknown *iface)
310 return CONTAINING_RECORD(iface, struct session_op, IUnknown_iface);
313 static struct quality_manager *impl_from_IMFQualityManager(IMFQualityManager *iface)
315 return CONTAINING_RECORD(iface, struct quality_manager, IMFQualityManager_iface);
318 static struct quality_manager *impl_from_qm_IMFClockStateSink(IMFClockStateSink *iface)
320 return CONTAINING_RECORD(iface, struct quality_manager, IMFClockStateSink_iface);
323 static struct topo_node *impl_node_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify *iface)
325 return CONTAINING_RECORD(iface, struct topo_node, u.sink.notify_cb);
328 /* IMFLocalMFTRegistration */
329 static HRESULT WINAPI local_mft_registration_QueryInterface(IMFLocalMFTRegistration *iface, REFIID riid, void **obj)
331 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
333 if (IsEqualIID(riid, &IID_IMFLocalMFTRegistration) ||
334 IsEqualIID(riid, &IID_IUnknown))
336 *obj = iface;
337 IMFLocalMFTRegistration_AddRef(iface);
338 return S_OK;
341 WARN("Unexpected %s.\n", debugstr_guid(riid));
342 *obj = NULL;
343 return E_NOINTERFACE;
346 static ULONG WINAPI local_mft_registration_AddRef(IMFLocalMFTRegistration *iface)
348 return 2;
351 static ULONG WINAPI local_mft_registration_Release(IMFLocalMFTRegistration *iface)
353 return 1;
356 static HRESULT WINAPI local_mft_registration_RegisterMFTs(IMFLocalMFTRegistration *iface, MFT_REGISTRATION_INFO *info,
357 DWORD count)
359 HRESULT hr = S_OK;
360 DWORD i;
362 TRACE("%p, %p, %u.\n", iface, info, count);
364 for (i = 0; i < count; ++i)
366 if (FAILED(hr = MFTRegisterLocalByCLSID(&info[i].clsid, &info[i].guidCategory, info[i].pszName,
367 info[i].uiFlags, info[i].cInTypes, info[i].pInTypes, info[i].cOutTypes, info[i].pOutTypes)))
369 break;
373 return hr;
376 static const IMFLocalMFTRegistrationVtbl local_mft_registration_vtbl =
378 local_mft_registration_QueryInterface,
379 local_mft_registration_AddRef,
380 local_mft_registration_Release,
381 local_mft_registration_RegisterMFTs,
384 static IMFLocalMFTRegistration local_mft_registration = { &local_mft_registration_vtbl };
386 static HRESULT WINAPI session_op_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
388 if (IsEqualIID(riid, &IID_IUnknown))
390 *obj = iface;
391 IUnknown_AddRef(iface);
392 return S_OK;
395 *obj = NULL;
396 return E_NOINTERFACE;
399 static ULONG WINAPI session_op_AddRef(IUnknown *iface)
401 struct session_op *op = impl_op_from_IUnknown(iface);
402 ULONG refcount = InterlockedIncrement(&op->refcount);
404 TRACE("%p, refcount %u.\n", iface, refcount);
406 return refcount;
409 static ULONG WINAPI session_op_Release(IUnknown *iface)
411 struct session_op *op = impl_op_from_IUnknown(iface);
412 ULONG refcount = InterlockedDecrement(&op->refcount);
414 TRACE("%p, refcount %u.\n", iface, refcount);
416 if (!refcount)
418 switch (op->command)
420 case SESSION_CMD_SET_TOPOLOGY:
421 if (op->u.set_topology.topology)
422 IMFTopology_Release(op->u.set_topology.topology);
423 break;
424 case SESSION_CMD_START:
425 PropVariantClear(&op->u.start.start_position);
426 break;
427 case SESSION_CMD_QM_NOTIFY_TOPOLOGY:
428 if (op->u.notify_topology.topology)
429 IMFTopology_Release(op->u.notify_topology.topology);
430 break;
431 default:
434 heap_free(op);
437 return refcount;
440 static const IUnknownVtbl session_op_vtbl =
442 session_op_QueryInterface,
443 session_op_AddRef,
444 session_op_Release,
447 static HRESULT create_session_op(enum session_command command, struct session_op **ret)
449 struct session_op *op;
451 if (!(op = heap_alloc_zero(sizeof(*op))))
452 return E_OUTOFMEMORY;
454 op->IUnknown_iface.lpVtbl = &session_op_vtbl;
455 op->refcount = 1;
456 op->command = command;
458 *ret = op;
460 return S_OK;
463 static HRESULT session_is_shut_down(struct media_session *session)
465 return session->state == SESSION_STATE_SHUT_DOWN ? MF_E_SHUTDOWN : S_OK;
468 static void session_push_back_command(struct media_session *session, enum session_command command)
470 struct session_op *op;
472 if (SUCCEEDED(create_session_op(command, &op)))
473 list_add_head(&session->commands, &op->entry);
476 static HRESULT session_submit_command(struct media_session *session, struct session_op *op)
478 HRESULT hr;
480 EnterCriticalSection(&session->cs);
481 if (SUCCEEDED(hr = session_is_shut_down(session)))
483 if (list_empty(&session->commands))
484 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface);
485 list_add_tail(&session->commands, &op->entry);
486 IUnknown_AddRef(&op->IUnknown_iface);
488 LeaveCriticalSection(&session->cs);
490 return hr;
493 static HRESULT session_submit_simple_command(struct media_session *session, enum session_command command)
495 struct session_op *op;
496 HRESULT hr;
498 if (FAILED(hr = create_session_op(command, &op)))
499 return hr;
501 hr = session_submit_command(session, op);
502 IUnknown_Release(&op->IUnknown_iface);
503 return hr;
506 static void session_clear_topologies(struct media_session *session)
508 struct queued_topology *ptr, *next;
510 LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &session->topologies, struct queued_topology, entry)
512 list_remove(&ptr->entry);
513 IMFTopology_Release(ptr->topology);
514 heap_free(ptr);
518 static void session_set_topo_status(struct media_session *session, HRESULT status,
519 MF_TOPOSTATUS topo_status)
521 IMFMediaEvent *event;
522 PROPVARIANT param;
524 if (topo_status == MF_TOPOSTATUS_INVALID)
525 return;
527 if (list_empty(&session->topologies))
529 FIXME("Unexpectedly empty topology queue.\n");
530 return;
533 if (topo_status > session->presentation.topo_status)
535 struct queued_topology *topology = LIST_ENTRY(list_head(&session->topologies), struct queued_topology, entry);
537 param.vt = VT_UNKNOWN;
538 param.punkVal = (IUnknown *)topology->topology;
540 if (FAILED(MFCreateMediaEvent(MESessionTopologyStatus, &GUID_NULL, status, &param, &event)))
541 return;
543 session->presentation.topo_status = topo_status;
545 IMFMediaEvent_SetUINT32(event, &MF_EVENT_TOPOLOGY_STATUS, topo_status);
546 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
547 IMFMediaEvent_Release(event);
551 static HRESULT session_bind_output_nodes(IMFTopology *topology)
553 MF_TOPOLOGY_TYPE node_type;
554 IMFStreamSink *stream_sink;
555 IMFMediaSink *media_sink;
556 WORD node_count = 0, i;
557 IMFTopologyNode *node;
558 IMFActivate *activate;
559 UINT32 stream_id;
560 IUnknown *object;
561 HRESULT hr;
563 hr = IMFTopology_GetNodeCount(topology, &node_count);
565 for (i = 0; i < node_count; ++i)
567 if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
568 break;
570 if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type)) || node_type != MF_TOPOLOGY_OUTPUT_NODE)
572 IMFTopologyNode_Release(node);
573 continue;
576 if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object)))
578 stream_sink = NULL;
579 if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&stream_sink)))
581 if (SUCCEEDED(hr = IUnknown_QueryInterface(object, &IID_IMFActivate, (void **)&activate)))
583 if (SUCCEEDED(hr = IMFActivate_ActivateObject(activate, &IID_IMFMediaSink, (void **)&media_sink)))
585 if (FAILED(IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_STREAMID, &stream_id)))
586 stream_id = 0;
588 stream_sink = NULL;
589 if (FAILED(IMFMediaSink_GetStreamSinkById(media_sink, stream_id, &stream_sink)))
590 hr = IMFMediaSink_AddStreamSink(media_sink, stream_id, NULL, &stream_sink);
592 if (stream_sink)
593 hr = IMFTopologyNode_SetObject(node, (IUnknown *)stream_sink);
595 IMFMediaSink_Release(media_sink);
598 if (SUCCEEDED(hr))
599 IMFTopologyNode_SetUnknown(node, &_MF_TOPONODE_IMFActivate, (IUnknown *)activate);
601 IMFActivate_Release(activate);
605 if (stream_sink)
606 IMFStreamSink_Release(stream_sink);
607 IUnknown_Release(object);
610 IMFTopologyNode_Release(node);
613 return hr;
616 static void session_set_caps(struct media_session *session, DWORD caps)
618 DWORD delta = session->caps ^ caps;
619 IMFMediaEvent *event;
621 /* Delta is documented to reflect rate value changes as well, but it's not clear what to compare
622 them to, since session always queries for current object rates. */
623 if (!delta)
624 return;
626 session->caps = caps;
628 if (FAILED(MFCreateMediaEvent(MESessionCapabilitiesChanged, &GUID_NULL, S_OK, NULL, &event)))
629 return;
631 IMFMediaEvent_SetUINT32(event, &MF_EVENT_SESSIONCAPS, caps);
632 IMFMediaEvent_SetUINT32(event, &MF_EVENT_SESSIONCAPS_DELTA, delta);
634 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
635 IMFMediaEvent_Release(event);
638 static void transform_release_sample(struct sample *sample)
640 list_remove(&sample->entry);
641 if (sample->sample)
642 IMFSample_Release(sample->sample);
643 heap_free(sample);
646 static void transform_stream_drop_samples(struct transform_stream *stream)
648 struct sample *sample, *sample2;
650 LIST_FOR_EACH_ENTRY_SAFE(sample, sample2, &stream->samples, struct sample, entry)
651 transform_release_sample(sample);
654 static void release_topo_node(struct topo_node *node)
656 unsigned int i;
658 switch (node->type)
660 case MF_TOPOLOGY_SOURCESTREAM_NODE:
661 if (node->u.source.source)
662 IMFMediaSource_Release(node->u.source.source);
663 break;
664 case MF_TOPOLOGY_TRANSFORM_NODE:
665 for (i = 0; i < node->u.transform.input_count; ++i)
666 transform_stream_drop_samples(&node->u.transform.inputs[i]);
667 for (i = 0; i < node->u.transform.output_count; ++i)
668 transform_stream_drop_samples(&node->u.transform.outputs[i]);
669 heap_free(node->u.transform.inputs);
670 heap_free(node->u.transform.outputs);
671 heap_free(node->u.transform.input_map);
672 heap_free(node->u.transform.output_map);
673 break;
674 case MF_TOPOLOGY_OUTPUT_NODE:
675 if (node->u.sink.allocator)
676 IMFVideoSampleAllocator_Release(node->u.sink.allocator);
677 if (node->u.sink.allocator_cb)
679 IMFVideoSampleAllocatorCallback_SetCallback(node->u.sink.allocator_cb, NULL);
680 IMFVideoSampleAllocatorCallback_Release(node->u.sink.allocator_cb);
682 break;
683 default:
687 if (node->object.object)
688 IUnknown_Release(node->object.object);
689 if (node->node)
690 IMFTopologyNode_Release(node->node);
691 heap_free(node);
694 static void session_shutdown_current_topology(struct media_session *session)
696 unsigned int shutdown, force_shutdown;
697 MF_TOPOLOGY_TYPE node_type;
698 IMFStreamSink *stream_sink;
699 IMFTopology *topology;
700 IMFTopologyNode *node;
701 IMFActivate *activate;
702 IMFMediaSink *sink;
703 WORD idx = 0;
704 HRESULT hr;
706 topology = session->presentation.current_topology;
707 force_shutdown = session->state == SESSION_STATE_SHUT_DOWN;
709 /* FIXME: should handle async MFTs, but these are not supported by the rest of the pipeline currently. */
711 while (SUCCEEDED(IMFTopology_GetNode(topology, idx++, &node)))
713 if (SUCCEEDED(IMFTopologyNode_GetNodeType(node, &node_type)) &&
714 node_type == MF_TOPOLOGY_OUTPUT_NODE)
716 shutdown = 1;
717 IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, &shutdown);
719 if (force_shutdown || shutdown)
721 if (SUCCEEDED(IMFTopologyNode_GetUnknown(node, &_MF_TOPONODE_IMFActivate, &IID_IMFActivate,
722 (void **)&activate)))
724 if (FAILED(hr = IMFActivate_ShutdownObject(activate)))
725 WARN("Failed to shut down activation object for the sink, hr %#x.\n", hr);
726 IMFActivate_Release(activate);
728 else if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink)))
730 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink)))
732 IMFMediaSink_Shutdown(sink);
733 IMFMediaSink_Release(sink);
736 IMFStreamSink_Release(stream_sink);
741 IMFTopologyNode_Release(node);
745 static void session_clear_command_list(struct media_session *session)
747 struct session_op *op, *op2;
749 LIST_FOR_EACH_ENTRY_SAFE(op, op2, &session->commands, struct session_op, entry)
751 list_remove(&op->entry);
752 IUnknown_Release(&op->IUnknown_iface);
756 static void session_clear_presentation(struct media_session *session)
758 struct media_source *source, *source2;
759 struct media_sink *sink, *sink2;
760 struct topo_node *node, *node2;
762 session_shutdown_current_topology(session);
764 IMFTopology_Clear(session->presentation.current_topology);
765 session->presentation.topo_status = MF_TOPOSTATUS_INVALID;
767 LIST_FOR_EACH_ENTRY_SAFE(source, source2, &session->presentation.sources, struct media_source, entry)
769 list_remove(&source->entry);
770 if (source->source)
771 IMFMediaSource_Release(source->source);
772 if (source->pd)
773 IMFPresentationDescriptor_Release(source->pd);
774 heap_free(source);
777 LIST_FOR_EACH_ENTRY_SAFE(node, node2, &session->presentation.nodes, struct topo_node, entry)
779 list_remove(&node->entry);
780 release_topo_node(node);
783 LIST_FOR_EACH_ENTRY_SAFE(sink, sink2, &session->presentation.sinks, struct media_sink, entry)
785 list_remove(&sink->entry);
787 if (sink->sink)
788 IMFMediaSink_Release(sink->sink);
789 if (sink->preroll)
790 IMFMediaSinkPreroll_Release(sink->preroll);
791 if (sink->event_generator)
792 IMFMediaEventGenerator_Release(sink->event_generator);
793 heap_free(sink);
797 static struct topo_node *session_get_node_by_id(const struct media_session *session, TOPOID id)
799 struct topo_node *node;
801 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
803 if (node->node_id == id)
804 return node;
807 return NULL;
810 static void session_start(struct media_session *session, const GUID *time_format, const PROPVARIANT *start_position)
812 struct media_source *source;
813 HRESULT hr;
815 switch (session->state)
817 case SESSION_STATE_STOPPED:
818 case SESSION_STATE_PAUSED:
820 session->presentation.time_format = *time_format;
821 session->presentation.start_position.vt = VT_EMPTY;
822 PropVariantCopy(&session->presentation.start_position, start_position);
824 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
826 if (!(session->presentation.flags & SESSION_FLAG_SOURCES_SUBSCRIBED))
828 if (FAILED(hr = IMFMediaSource_BeginGetEvent(source->source, &session->events_callback,
829 (IUnknown *)source->source)))
831 WARN("Failed to subscribe to source events, hr %#x.\n", hr);
835 if (FAILED(hr = IMFMediaSource_Start(source->source, source->pd, &GUID_NULL, start_position)))
836 WARN("Failed to start media source %p, hr %#x.\n", source->source, hr);
839 session->presentation.flags |= SESSION_FLAG_SOURCES_SUBSCRIBED;
840 session->state = SESSION_STATE_STARTING_SOURCES;
841 break;
842 case SESSION_STATE_STARTED:
843 FIXME("Seeking is not implemented.\n");
844 break;
845 case SESSION_STATE_CLOSED:
846 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStarted, &GUID_NULL,
847 MF_E_INVALIDREQUEST, NULL);
848 break;
849 default:
854 static void session_command_complete(struct media_session *session)
856 struct session_op *op;
857 struct list *e;
859 /* Pop current command, submit next. */
860 if ((e = list_head(&session->commands)))
862 op = LIST_ENTRY(e, struct session_op, entry);
863 list_remove(&op->entry);
864 IUnknown_Release(&op->IUnknown_iface);
867 if ((e = list_head(&session->commands)))
869 op = LIST_ENTRY(e, struct session_op, entry);
870 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface);
874 static void session_set_started(struct media_session *session)
876 struct media_source *source;
877 unsigned int caps, flags;
878 IMFMediaEvent *event;
880 session->state = SESSION_STATE_STARTED;
882 caps = session->caps | MFSESSIONCAP_PAUSE;
884 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
886 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source->source, &flags)))
888 if (!(flags & MFMEDIASOURCE_CAN_PAUSE))
890 caps &= ~MFSESSIONCAP_PAUSE;
891 break;
896 session_set_caps(session, caps);
898 if (SUCCEEDED(MFCreateMediaEvent(MESessionStarted, &GUID_NULL, S_OK, NULL, &event)))
900 IMFMediaEvent_SetUINT64(event, &MF_EVENT_PRESENTATION_TIME_OFFSET, 0);
901 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
902 IMFMediaEvent_Release(event);
904 session_command_complete(session);
907 static void session_set_paused(struct media_session *session, HRESULT status)
909 session->state = SESSION_STATE_PAUSED;
910 if (SUCCEEDED(status))
911 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
912 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionPaused, &GUID_NULL, status, NULL);
913 session_command_complete(session);
916 static void session_set_closed(struct media_session *session, HRESULT status)
918 session->state = SESSION_STATE_CLOSED;
919 if (SUCCEEDED(status))
920 session_set_caps(session, session->caps & ~(MFSESSIONCAP_START | MFSESSIONCAP_SEEK));
921 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionClosed, &GUID_NULL, status, NULL);
922 session_command_complete(session);
925 static void session_pause(struct media_session *session)
927 HRESULT hr;
929 switch (session->state)
931 case SESSION_STATE_STARTED:
933 /* Transition in two steps - pause the clock, wait for sinks, then pause sources. */
934 if (SUCCEEDED(hr = IMFPresentationClock_Pause(session->clock)))
935 session->state = SESSION_STATE_PAUSING_SINKS;
937 break;
938 default:
939 hr = MF_E_INVALIDREQUEST;
942 if (FAILED(hr))
943 session_set_paused(session, hr);
946 static void session_set_stopped(struct media_session *session, HRESULT status)
948 MediaEventType event_type;
949 IMFMediaEvent *event;
951 session->state = SESSION_STATE_STOPPED;
952 event_type = session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION ? MESessionEnded : MESessionStopped;
954 if (SUCCEEDED(MFCreateMediaEvent(event_type, &GUID_NULL, status, NULL, &event)))
956 IMFMediaEvent_SetUINT64(event, &MF_SESSION_APPROX_EVENT_OCCURRENCE_TIME, session->presentation.clock_stop_time);
957 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
958 IMFMediaEvent_Release(event);
960 session_command_complete(session);
963 static void session_stop(struct media_session *session)
965 HRESULT hr = MF_E_INVALIDREQUEST;
967 switch (session->state)
969 case SESSION_STATE_STARTED:
970 case SESSION_STATE_PAUSED:
972 /* Transition in two steps - stop the clock, wait for sinks, then stop sources. */
973 IMFPresentationClock_GetTime(session->clock, &session->presentation.clock_stop_time);
974 if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock)))
975 session->state = SESSION_STATE_STOPPING_SINKS;
976 else
977 session_set_stopped(session, hr);
979 break;
980 case SESSION_STATE_STOPPED:
981 hr = S_OK;
982 /* fallthrough */
983 default:
984 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStopped, &GUID_NULL, hr, NULL);
985 session_command_complete(session);
986 break;
990 static HRESULT session_finalize_sinks(struct media_session *session)
992 IMFFinalizableMediaSink *fin_sink;
993 BOOL sinks_finalized = TRUE;
994 struct media_sink *sink;
995 HRESULT hr = S_OK;
997 session->presentation.flags &= ~SESSION_FLAG_FINALIZE_SINKS;
998 session->state = SESSION_STATE_FINALIZING_SINKS;
1000 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
1002 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink->sink, &IID_IMFFinalizableMediaSink, (void **)&fin_sink)))
1004 hr = IMFFinalizableMediaSink_BeginFinalize(fin_sink, &session->sink_finalizer_callback,
1005 (IUnknown *)fin_sink);
1006 IMFFinalizableMediaSink_Release(fin_sink);
1007 if (FAILED(hr))
1008 break;
1009 sinks_finalized = FALSE;
1011 else
1012 sink->finalized = TRUE;
1015 if (sinks_finalized)
1016 session_set_closed(session, hr);
1018 return hr;
1021 static void session_close(struct media_session *session)
1023 HRESULT hr = S_OK;
1025 switch (session->state)
1027 case SESSION_STATE_STOPPED:
1028 hr = session_finalize_sinks(session);
1029 break;
1030 case SESSION_STATE_STARTED:
1031 case SESSION_STATE_PAUSED:
1032 session->presentation.flags |= SESSION_FLAG_FINALIZE_SINKS;
1033 if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock)))
1034 session->state = SESSION_STATE_STOPPING_SINKS;
1035 break;
1036 default:
1037 hr = MF_E_INVALIDREQUEST;
1038 break;
1041 if (FAILED(hr))
1042 session_set_closed(session, hr);
1045 static struct media_source *session_get_media_source(struct media_session *session, IMFMediaSource *source)
1047 struct media_source *cur;
1049 LIST_FOR_EACH_ENTRY(cur, &session->presentation.sources, struct media_source, entry)
1051 if (source == cur->source)
1052 return cur;
1055 return NULL;
1058 static void session_release_media_source(struct media_source *source)
1060 IMFMediaSource_Release(source->source);
1061 if (source->pd)
1062 IMFPresentationDescriptor_Release(source->pd);
1063 heap_free(source);
1066 static HRESULT session_add_media_source(struct media_session *session, IMFTopologyNode *node, IMFMediaSource *source)
1068 struct media_source *media_source;
1069 HRESULT hr;
1071 if (session_get_media_source(session, source))
1072 return S_FALSE;
1074 if (!(media_source = heap_alloc_zero(sizeof(*media_source))))
1075 return E_OUTOFMEMORY;
1077 media_source->source = source;
1078 IMFMediaSource_AddRef(media_source->source);
1080 hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, &IID_IMFPresentationDescriptor,
1081 (void **)&media_source->pd);
1083 if (SUCCEEDED(hr))
1084 list_add_tail(&session->presentation.sources, &media_source->entry);
1085 else
1086 session_release_media_source(media_source);
1088 return hr;
1091 static void session_raise_topology_set(struct media_session *session, IMFTopology *topology, HRESULT status)
1093 PROPVARIANT param;
1095 param.vt = topology ? VT_UNKNOWN : VT_EMPTY;
1096 param.punkVal = (IUnknown *)topology;
1098 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologySet, &GUID_NULL, status, &param);
1101 static DWORD session_get_object_rate_caps(IUnknown *object)
1103 IMFRateSupport *rate_support;
1104 DWORD caps = 0;
1105 float rate;
1107 if (SUCCEEDED(MFGetService(object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support)))
1109 rate = 0.0f;
1110 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support, MFRATE_FORWARD, TRUE, &rate)) && rate != 0.0f)
1111 caps |= MFSESSIONCAP_RATE_FORWARD;
1113 rate = 0.0f;
1114 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support, MFRATE_REVERSE, TRUE, &rate)) && rate != 0.0f)
1115 caps |= MFSESSIONCAP_RATE_REVERSE;
1117 IMFRateSupport_Release(rate_support);
1120 return caps;
1123 static HRESULT session_add_media_sink(struct media_session *session, IMFTopologyNode *node, IMFMediaSink *sink)
1125 struct media_sink *media_sink;
1126 unsigned int disable_preroll = 0;
1127 DWORD flags;
1129 LIST_FOR_EACH_ENTRY(media_sink, &session->presentation.sinks, struct media_sink, entry)
1131 if (sink == media_sink->sink)
1132 return S_FALSE;
1135 if (!(media_sink = heap_alloc_zero(sizeof(*media_sink))))
1136 return E_OUTOFMEMORY;
1138 media_sink->sink = sink;
1139 IMFMediaSink_AddRef(media_sink->sink);
1141 IMFMediaSink_QueryInterface(media_sink->sink, &IID_IMFMediaEventGenerator, (void **)&media_sink->event_generator);
1143 IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_DISABLE_PREROLL, &disable_preroll);
1144 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink, &flags)) && flags & MEDIASINK_CAN_PREROLL && !disable_preroll)
1146 if (SUCCEEDED(IMFMediaSink_QueryInterface(media_sink->sink, &IID_IMFMediaSinkPreroll, (void **)&media_sink->preroll)))
1147 session->presentation.flags |= SESSION_FLAG_NEEDS_PREROLL;
1150 list_add_tail(&session->presentation.sinks, &media_sink->entry);
1152 return S_OK;
1155 static unsigned int transform_node_get_stream_id(struct topo_node *node, BOOL output, unsigned int index)
1157 unsigned int *map = output ? node->u.transform.output_map : node->u.transform.input_map;
1158 return map ? map[index] : index;
1161 static HRESULT session_set_transform_stream_info(struct topo_node *node)
1163 unsigned int *input_map = NULL, *output_map = NULL;
1164 unsigned int i, input_count, output_count, block_alignment;
1165 struct transform_stream *streams;
1166 IMFMediaType *media_type;
1167 GUID major = { 0 };
1168 HRESULT hr;
1170 hr = IMFTransform_GetStreamCount(node->object.transform, &input_count, &output_count);
1171 if (SUCCEEDED(hr) && (input_count > 1 || output_count > 1))
1173 input_map = heap_calloc(input_count, sizeof(*input_map));
1174 output_map = heap_calloc(output_count, sizeof(*output_map));
1175 if (FAILED(IMFTransform_GetStreamIDs(node->object.transform, input_count, input_map,
1176 output_count, output_map)))
1178 /* Assume sequential identifiers. */
1179 heap_free(input_map);
1180 heap_free(output_map);
1181 input_map = output_map = NULL;
1185 if (SUCCEEDED(hr))
1187 node->u.transform.input_map = input_map;
1188 node->u.transform.output_map = output_map;
1190 streams = heap_calloc(input_count, sizeof(*streams));
1191 for (i = 0; i < input_count; ++i)
1192 list_init(&streams[i].samples);
1193 node->u.transform.inputs = streams;
1194 node->u.transform.input_count = input_count;
1196 streams = heap_calloc(output_count, sizeof(*streams));
1197 for (i = 0; i < output_count; ++i)
1199 list_init(&streams[i].samples);
1201 if (SUCCEEDED(IMFTransform_GetOutputCurrentType(node->object.transform,
1202 transform_node_get_stream_id(node, TRUE, i), &media_type)))
1204 if (SUCCEEDED(IMFMediaType_GetMajorType(media_type, &major)) && IsEqualGUID(&major, &MFMediaType_Audio)
1205 && SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment)))
1207 streams[i].min_buffer_size = block_alignment;
1209 IMFMediaType_Release(media_type);
1212 node->u.transform.outputs = streams;
1213 node->u.transform.output_count = output_count;
1216 return hr;
1219 static HRESULT session_get_stream_sink_type(IMFStreamSink *sink, IMFMediaType **media_type)
1221 IMFMediaTypeHandler *handler;
1222 HRESULT hr;
1224 if (SUCCEEDED(hr = IMFStreamSink_GetMediaTypeHandler(sink, &handler)))
1226 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, media_type);
1227 IMFMediaTypeHandler_Release(handler);
1230 return hr;
1233 static HRESULT WINAPI node_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify *iface,
1234 REFIID riid, void **obj)
1236 if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorNotify) ||
1237 IsEqualIID(riid, &IID_IUnknown))
1239 *obj = iface;
1240 IMFVideoSampleAllocatorNotify_AddRef(iface);
1241 return S_OK;
1244 *obj = NULL;
1245 return E_NOINTERFACE;
1248 static ULONG WINAPI node_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify *iface)
1250 return 2;
1253 static ULONG WINAPI node_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify *iface)
1255 return 1;
1258 static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output);
1260 static HRESULT WINAPI node_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify *iface)
1262 struct topo_node *topo_node = impl_node_from_IMFVideoSampleAllocatorNotify(iface);
1263 struct session_op *op;
1265 if (SUCCEEDED(create_session_op(SESSION_CMD_SA_READY, &op)))
1267 op->u.sa_ready.node_id = topo_node->node_id;
1268 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &topo_node->session->commands_callback, &op->IUnknown_iface);
1269 IUnknown_Release(&op->IUnknown_iface);
1272 return S_OK;
1275 static const IMFVideoSampleAllocatorNotifyVtbl node_sample_allocator_cb_vtbl =
1277 node_sample_allocator_cb_QueryInterface,
1278 node_sample_allocator_cb_AddRef,
1279 node_sample_allocator_cb_Release,
1280 node_sample_allocator_cb_NotifyRelease,
1283 static HRESULT session_append_node(struct media_session *session, IMFTopologyNode *node)
1285 struct topo_node *topo_node;
1286 IMFMediaSink *media_sink;
1287 IMFMediaType *media_type;
1288 IMFStreamDescriptor *sd;
1289 HRESULT hr = S_OK;
1291 if (!(topo_node = heap_alloc_zero(sizeof(*topo_node))))
1292 return E_OUTOFMEMORY;
1294 IMFTopologyNode_GetNodeType(node, &topo_node->type);
1295 IMFTopologyNode_GetTopoNodeID(node, &topo_node->node_id);
1296 topo_node->node = node;
1297 IMFTopologyNode_AddRef(topo_node->node);
1298 topo_node->session = session;
1300 switch (topo_node->type)
1302 case MF_TOPOLOGY_OUTPUT_NODE:
1303 topo_node->u.sink.notify_cb.lpVtbl = &node_sample_allocator_cb_vtbl;
1305 if (FAILED(hr = topology_node_get_object(node, &IID_IMFStreamSink, (void **)&topo_node->object.object)))
1307 WARN("Failed to get stream sink interface, hr %#x.\n", hr);
1308 break;
1311 if (FAILED(hr = IMFStreamSink_GetMediaSink(topo_node->object.sink_stream, &media_sink)))
1312 break;
1314 if (SUCCEEDED(hr = session_add_media_sink(session, node, media_sink)))
1316 if (SUCCEEDED(session_get_stream_sink_type(topo_node->object.sink_stream, &media_type)))
1318 if (SUCCEEDED(MFGetService(topo_node->object.object, &MR_VIDEO_ACCELERATION_SERVICE,
1319 &IID_IMFVideoSampleAllocator, (void **)&topo_node->u.sink.allocator)))
1321 if (FAILED(hr = IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node->u.sink.allocator,
1322 2, media_type)))
1324 WARN("Failed to initialize sample allocator for the stream, hr %#x.\n", hr);
1326 IMFVideoSampleAllocator_QueryInterface(topo_node->u.sink.allocator,
1327 &IID_IMFVideoSampleAllocatorCallback, (void **)&topo_node->u.sink.allocator_cb);
1328 IMFVideoSampleAllocatorCallback_SetCallback(topo_node->u.sink.allocator_cb,
1329 &topo_node->u.sink.notify_cb);
1331 IMFMediaType_Release(media_type);
1334 IMFMediaSink_Release(media_sink);
1336 break;
1337 case MF_TOPOLOGY_SOURCESTREAM_NODE:
1338 if (FAILED(IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_SOURCE, &IID_IMFMediaSource,
1339 (void **)&topo_node->u.source.source)))
1341 WARN("Missing MF_TOPONODE_SOURCE, hr %#x.\n", hr);
1342 break;
1345 if (FAILED(hr = session_add_media_source(session, node, topo_node->u.source.source)))
1346 break;
1348 if (FAILED(hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR,
1349 &IID_IMFStreamDescriptor, (void **)&sd)))
1351 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#x.\n", hr);
1352 break;
1355 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &topo_node->u.source.stream_id);
1356 IMFStreamDescriptor_Release(sd);
1358 break;
1359 case MF_TOPOLOGY_TRANSFORM_NODE:
1361 if (SUCCEEDED(hr = topology_node_get_object(node, &IID_IMFTransform, (void **)&topo_node->object.transform)))
1363 hr = session_set_transform_stream_info(topo_node);
1365 else
1366 WARN("Failed to get IMFTransform for MFT node, hr %#x.\n", hr);
1368 break;
1369 case MF_TOPOLOGY_TEE_NODE:
1370 FIXME("Unsupported node type %d.\n", topo_node->type);
1372 break;
1373 default:
1377 if (SUCCEEDED(hr))
1378 list_add_tail(&session->presentation.nodes, &topo_node->entry);
1379 else
1380 release_topo_node(topo_node);
1382 return hr;
1385 static HRESULT session_collect_nodes(struct media_session *session)
1387 IMFTopology *topology = session->presentation.current_topology;
1388 IMFTopologyNode *node;
1389 WORD i, count = 0;
1390 HRESULT hr;
1392 if (!list_empty(&session->presentation.nodes))
1393 return S_OK;
1395 if (FAILED(hr = IMFTopology_GetNodeCount(topology, &count)))
1396 return hr;
1398 for (i = 0; i < count; ++i)
1400 if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
1402 WARN("Failed to get node %u.\n", i);
1403 break;
1406 hr = session_append_node(session, node);
1407 IMFTopologyNode_Release(node);
1408 if (FAILED(hr))
1410 WARN("Failed to add node %u.\n", i);
1411 break;
1415 return hr;
1418 static HRESULT session_set_current_topology(struct media_session *session, IMFTopology *topology)
1420 struct media_source *source;
1421 DWORD caps, object_flags;
1422 struct media_sink *sink;
1423 struct topo_node *node;
1424 struct session_op *op;
1425 IMFMediaEvent *event;
1426 HRESULT hr;
1428 if (session->quality_manager)
1430 if (SUCCEEDED(create_session_op(SESSION_CMD_QM_NOTIFY_TOPOLOGY, &op)))
1432 op->u.notify_topology.topology = topology;
1433 IMFTopology_AddRef(op->u.notify_topology.topology);
1434 session_submit_command(session, op);
1435 IUnknown_Release(&op->IUnknown_iface);
1439 if (FAILED(hr = IMFTopology_CloneFrom(session->presentation.current_topology, topology)))
1441 WARN("Failed to clone topology, hr %#x.\n", hr);
1442 return hr;
1445 session_collect_nodes(session);
1447 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
1449 if (node->type == MF_TOPOLOGY_TRANSFORM_NODE)
1451 if (FAILED(hr = IMFTransform_ProcessMessage(node->object.transform,
1452 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0)))
1453 return hr;
1457 /* FIXME: attributes are all zero for now */
1458 if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime, &GUID_NULL, S_OK, NULL, &event)))
1460 IMFMediaEvent_SetUINT64(event, &MF_EVENT_START_PRESENTATION_TIME, 0);
1461 IMFMediaEvent_SetUINT64(event, &MF_EVENT_PRESENTATION_TIME_OFFSET, 0);
1462 IMFMediaEvent_SetUINT64(event, &MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT, 0);
1464 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
1465 IMFMediaEvent_Release(event);
1468 /* Update session caps. */
1469 caps = MFSESSIONCAP_START | MFSESSIONCAP_SEEK | MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE |
1470 MFSESSIONCAP_DOES_NOT_USE_NETWORK;
1472 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
1474 if (!caps)
1475 break;
1477 object_flags = 0;
1478 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source->source, &object_flags)))
1480 if (!(object_flags & MFMEDIASOURCE_DOES_NOT_USE_NETWORK))
1481 caps &= ~MFSESSIONCAP_DOES_NOT_USE_NETWORK;
1482 if (!(object_flags & MFMEDIASOURCE_CAN_SEEK))
1483 caps &= ~MFSESSIONCAP_SEEK;
1486 /* Mask unsupported rate caps. */
1488 caps &= session_get_object_rate_caps((IUnknown *)source->source)
1489 | ~(MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE);
1492 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
1494 if (!caps)
1495 break;
1497 object_flags = 0;
1498 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink->sink, &object_flags)))
1500 if (!(object_flags & MEDIASINK_RATELESS))
1501 caps &= session_get_object_rate_caps((IUnknown *)sink->sink)
1502 | ~(MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE);
1506 session_set_caps(session, caps);
1508 return S_OK;
1511 static void session_set_topology(struct media_session *session, DWORD flags, IMFTopology *topology)
1513 IMFTopology *resolved_topology = NULL;
1514 HRESULT hr = S_OK;
1516 /* Resolve unless claimed to be full. */
1517 if (!(flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT) && topology)
1519 if (!(flags & MFSESSION_SETTOPOLOGY_NORESOLUTION))
1521 hr = session_bind_output_nodes(topology);
1523 if (SUCCEEDED(hr))
1524 hr = IMFTopoLoader_Load(session->topo_loader, topology, &resolved_topology, NULL /* FIXME? */);
1526 if (SUCCEEDED(hr))
1528 topology = resolved_topology;
1533 if (flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT)
1535 if ((topology && topology == session->presentation.current_topology) || !topology)
1537 /* FIXME: stop current topology, queue next one. */
1538 session_clear_presentation(session);
1540 else
1541 hr = S_FALSE;
1543 topology = NULL;
1545 else if (topology && flags & MFSESSION_SETTOPOLOGY_IMMEDIATE)
1547 session_clear_topologies(session);
1548 session_clear_presentation(session);
1551 session_raise_topology_set(session, topology, hr);
1553 /* With no current topology set it right away, otherwise queue. */
1554 if (topology)
1556 struct queued_topology *queued_topology;
1558 if ((queued_topology = heap_alloc_zero(sizeof(*queued_topology))))
1560 queued_topology->topology = topology;
1561 IMFTopology_AddRef(queued_topology->topology);
1563 list_add_tail(&session->topologies, &queued_topology->entry);
1566 if (session->presentation.topo_status == MF_TOPOSTATUS_INVALID)
1568 hr = session_set_current_topology(session, topology);
1569 session_set_topo_status(session, hr, MF_TOPOSTATUS_READY);
1573 if (resolved_topology)
1574 IMFTopology_Release(resolved_topology);
1577 static HRESULT WINAPI mfsession_QueryInterface(IMFMediaSession *iface, REFIID riid, void **out)
1579 struct media_session *session = impl_from_IMFMediaSession(iface);
1581 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1583 if (IsEqualIID(riid, &IID_IMFMediaSession) ||
1584 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
1585 IsEqualIID(riid, &IID_IUnknown))
1587 *out = &session->IMFMediaSession_iface;
1588 IMFMediaSession_AddRef(iface);
1589 return S_OK;
1591 else if (IsEqualIID(riid, &IID_IMFGetService))
1593 *out = &session->IMFGetService_iface;
1594 IMFMediaSession_AddRef(iface);
1595 return S_OK;
1598 WARN("Unsupported %s.\n", debugstr_guid(riid));
1599 *out = NULL;
1600 return E_NOINTERFACE;
1603 static ULONG WINAPI mfsession_AddRef(IMFMediaSession *iface)
1605 struct media_session *session = impl_from_IMFMediaSession(iface);
1606 ULONG refcount = InterlockedIncrement(&session->refcount);
1608 TRACE("%p, refcount %u.\n", iface, refcount);
1610 return refcount;
1613 static ULONG WINAPI mfsession_Release(IMFMediaSession *iface)
1615 struct media_session *session = impl_from_IMFMediaSession(iface);
1616 ULONG refcount = InterlockedDecrement(&session->refcount);
1618 TRACE("%p, refcount %u.\n", iface, refcount);
1620 if (!refcount)
1622 session_clear_topologies(session);
1623 session_clear_presentation(session);
1624 session_clear_command_list(session);
1625 if (session->presentation.current_topology)
1626 IMFTopology_Release(session->presentation.current_topology);
1627 if (session->event_queue)
1628 IMFMediaEventQueue_Release(session->event_queue);
1629 if (session->clock)
1630 IMFPresentationClock_Release(session->clock);
1631 if (session->system_time_source)
1632 IMFPresentationTimeSource_Release(session->system_time_source);
1633 if (session->clock_rate_control)
1634 IMFRateControl_Release(session->clock_rate_control);
1635 if (session->topo_loader)
1636 IMFTopoLoader_Release(session->topo_loader);
1637 if (session->quality_manager)
1638 IMFQualityManager_Release(session->quality_manager);
1639 DeleteCriticalSection(&session->cs);
1640 heap_free(session);
1643 return refcount;
1646 static HRESULT WINAPI mfsession_GetEvent(IMFMediaSession *iface, DWORD flags, IMFMediaEvent **event)
1648 struct media_session *session = impl_from_IMFMediaSession(iface);
1650 TRACE("%p, %#x, %p.\n", iface, flags, event);
1652 return IMFMediaEventQueue_GetEvent(session->event_queue, flags, event);
1655 static HRESULT WINAPI mfsession_BeginGetEvent(IMFMediaSession *iface, IMFAsyncCallback *callback, IUnknown *state)
1657 struct media_session *session = impl_from_IMFMediaSession(iface);
1659 TRACE("%p, %p, %p.\n", iface, callback, state);
1661 return IMFMediaEventQueue_BeginGetEvent(session->event_queue, callback, state);
1664 static HRESULT WINAPI mfsession_EndGetEvent(IMFMediaSession *iface, IMFAsyncResult *result, IMFMediaEvent **event)
1666 struct media_session *session = impl_from_IMFMediaSession(iface);
1668 TRACE("%p, %p, %p.\n", iface, result, event);
1670 return IMFMediaEventQueue_EndGetEvent(session->event_queue, result, event);
1673 static HRESULT WINAPI mfsession_QueueEvent(IMFMediaSession *iface, MediaEventType event_type, REFGUID ext_type,
1674 HRESULT hr, const PROPVARIANT *value)
1676 struct media_session *session = impl_from_IMFMediaSession(iface);
1678 TRACE("%p, %d, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
1680 return IMFMediaEventQueue_QueueEventParamVar(session->event_queue, event_type, ext_type, hr, value);
1683 static HRESULT WINAPI mfsession_SetTopology(IMFMediaSession *iface, DWORD flags, IMFTopology *topology)
1685 struct media_session *session = impl_from_IMFMediaSession(iface);
1686 struct session_op *op;
1687 WORD node_count = 0;
1688 HRESULT hr;
1690 TRACE("%p, %#x, %p.\n", iface, flags, topology);
1692 if (topology)
1694 if (FAILED(IMFTopology_GetNodeCount(topology, &node_count)) || node_count == 0)
1695 return E_INVALIDARG;
1698 if (FAILED(hr = create_session_op(SESSION_CMD_SET_TOPOLOGY, &op)))
1699 return hr;
1701 op->u.set_topology.flags = flags;
1702 op->u.set_topology.topology = topology;
1703 if (op->u.set_topology.topology)
1704 IMFTopology_AddRef(op->u.set_topology.topology);
1706 hr = session_submit_command(session, op);
1707 IUnknown_Release(&op->IUnknown_iface);
1709 return hr;
1712 static HRESULT WINAPI mfsession_ClearTopologies(IMFMediaSession *iface)
1714 struct media_session *session = impl_from_IMFMediaSession(iface);
1716 TRACE("%p.\n", iface);
1718 return session_submit_simple_command(session, SESSION_CMD_CLEAR_TOPOLOGIES);
1721 static HRESULT WINAPI mfsession_Start(IMFMediaSession *iface, const GUID *format, const PROPVARIANT *start_position)
1723 struct media_session *session = impl_from_IMFMediaSession(iface);
1724 struct session_op *op;
1725 HRESULT hr;
1727 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), start_position);
1729 if (!start_position)
1730 return E_POINTER;
1732 if (FAILED(hr = create_session_op(SESSION_CMD_START, &op)))
1733 return hr;
1735 op->u.start.time_format = format ? *format : GUID_NULL;
1736 hr = PropVariantCopy(&op->u.start.start_position, start_position);
1738 if (SUCCEEDED(hr))
1739 hr = session_submit_command(session, op);
1741 IUnknown_Release(&op->IUnknown_iface);
1742 return hr;
1745 static HRESULT WINAPI mfsession_Pause(IMFMediaSession *iface)
1747 struct media_session *session = impl_from_IMFMediaSession(iface);
1749 TRACE("%p.\n", iface);
1751 return session_submit_simple_command(session, SESSION_CMD_PAUSE);
1754 static HRESULT WINAPI mfsession_Stop(IMFMediaSession *iface)
1756 struct media_session *session = impl_from_IMFMediaSession(iface);
1758 TRACE("%p.\n", iface);
1760 return session_submit_simple_command(session, SESSION_CMD_STOP);
1763 static HRESULT WINAPI mfsession_Close(IMFMediaSession *iface)
1765 struct media_session *session = impl_from_IMFMediaSession(iface);
1767 TRACE("%p.\n", iface);
1769 return session_submit_simple_command(session, SESSION_CMD_CLOSE);
1772 static HRESULT WINAPI mfsession_Shutdown(IMFMediaSession *iface)
1774 struct media_session *session = impl_from_IMFMediaSession(iface);
1775 HRESULT hr = S_OK;
1777 TRACE("%p.\n", iface);
1779 EnterCriticalSection(&session->cs);
1780 if (SUCCEEDED(hr = session_is_shut_down(session)))
1782 session->state = SESSION_STATE_SHUT_DOWN;
1783 IMFMediaEventQueue_Shutdown(session->event_queue);
1784 if (session->quality_manager)
1785 IMFQualityManager_Shutdown(session->quality_manager);
1786 MFShutdownObject((IUnknown *)session->clock);
1787 IMFPresentationClock_Release(session->clock);
1788 session->clock = NULL;
1789 session_clear_presentation(session);
1790 session_clear_command_list(session);
1792 LeaveCriticalSection(&session->cs);
1794 return hr;
1797 static HRESULT WINAPI mfsession_GetClock(IMFMediaSession *iface, IMFClock **clock)
1799 struct media_session *session = impl_from_IMFMediaSession(iface);
1800 HRESULT hr;
1802 TRACE("%p, %p.\n", iface, clock);
1804 EnterCriticalSection(&session->cs);
1805 if (SUCCEEDED(hr = session_is_shut_down(session)))
1807 *clock = (IMFClock *)session->clock;
1808 IMFClock_AddRef(*clock);
1810 LeaveCriticalSection(&session->cs);
1812 return hr;
1815 static HRESULT WINAPI mfsession_GetSessionCapabilities(IMFMediaSession *iface, DWORD *caps)
1817 struct media_session *session = impl_from_IMFMediaSession(iface);
1818 HRESULT hr = S_OK;
1820 TRACE("%p, %p.\n", iface, caps);
1822 if (!caps)
1823 return E_POINTER;
1825 EnterCriticalSection(&session->cs);
1826 if (SUCCEEDED(hr = session_is_shut_down(session)))
1827 *caps = session->caps;
1828 LeaveCriticalSection(&session->cs);
1830 return hr;
1833 static HRESULT WINAPI mfsession_GetFullTopology(IMFMediaSession *iface, DWORD flags, TOPOID id, IMFTopology **topology)
1835 struct media_session *session = impl_from_IMFMediaSession(iface);
1836 struct queued_topology *queued;
1837 TOPOID topo_id;
1838 HRESULT hr;
1840 TRACE("%p, %#x, %s, %p.\n", iface, flags, wine_dbgstr_longlong(id), topology);
1842 *topology = NULL;
1844 EnterCriticalSection(&session->cs);
1846 if (SUCCEEDED(hr = session_is_shut_down(session)))
1848 if (flags & MFSESSION_GETFULLTOPOLOGY_CURRENT)
1850 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
1851 *topology = session->presentation.current_topology;
1852 else
1853 hr = MF_E_INVALIDREQUEST;
1855 else
1857 LIST_FOR_EACH_ENTRY(queued, &session->topologies, struct queued_topology, entry)
1859 if (SUCCEEDED(IMFTopology_GetTopologyID(queued->topology, &topo_id)) && topo_id == id)
1861 *topology = queued->topology;
1862 break;
1867 if (*topology)
1868 IMFTopology_AddRef(*topology);
1871 LeaveCriticalSection(&session->cs);
1873 return hr;
1876 static const IMFMediaSessionVtbl mfmediasessionvtbl =
1878 mfsession_QueryInterface,
1879 mfsession_AddRef,
1880 mfsession_Release,
1881 mfsession_GetEvent,
1882 mfsession_BeginGetEvent,
1883 mfsession_EndGetEvent,
1884 mfsession_QueueEvent,
1885 mfsession_SetTopology,
1886 mfsession_ClearTopologies,
1887 mfsession_Start,
1888 mfsession_Pause,
1889 mfsession_Stop,
1890 mfsession_Close,
1891 mfsession_Shutdown,
1892 mfsession_GetClock,
1893 mfsession_GetSessionCapabilities,
1894 mfsession_GetFullTopology,
1897 static HRESULT WINAPI session_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1899 struct media_session *session = impl_from_IMFGetService(iface);
1900 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
1903 static ULONG WINAPI session_get_service_AddRef(IMFGetService *iface)
1905 struct media_session *session = impl_from_IMFGetService(iface);
1906 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
1909 static ULONG WINAPI session_get_service_Release(IMFGetService *iface)
1911 struct media_session *session = impl_from_IMFGetService(iface);
1912 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
1915 static HRESULT session_get_video_render_service(struct media_session *session, REFGUID service,
1916 REFIID riid, void **obj)
1918 IMFStreamSink *stream_sink;
1919 IMFTopologyNode *node;
1920 IMFCollection *nodes;
1921 IMFMediaSink *sink;
1922 unsigned int i = 0;
1923 IUnknown *vr;
1924 HRESULT hr = E_FAIL;
1926 /* Use first sink to support IMFVideoRenderer. */
1927 if (session->presentation.current_topology)
1929 if (SUCCEEDED(IMFTopology_GetOutputNodeCollection(session->presentation.current_topology,
1930 &nodes)))
1932 while (IMFCollection_GetElement(nodes, i++, (IUnknown **)&node) == S_OK)
1934 if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink)))
1936 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink)))
1938 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink, &IID_IMFVideoRenderer, (void **)&vr)))
1940 if (FAILED(hr = MFGetService(vr, service, riid, obj)))
1941 WARN("Failed to get service from video renderer %#x.\n", hr);
1942 IUnknown_Release(vr);
1945 IMFStreamSink_Release(stream_sink);
1948 IMFTopologyNode_Release(node);
1950 if (*obj)
1951 break;
1954 IMFCollection_Release(nodes);
1958 return hr;
1961 static HRESULT WINAPI session_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
1963 struct media_session *session = impl_from_IMFGetService(iface);
1964 HRESULT hr = S_OK;
1966 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1968 *obj = NULL;
1970 EnterCriticalSection(&session->cs);
1971 if (FAILED(hr = session_is_shut_down(session)))
1974 else if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE))
1976 if (IsEqualIID(riid, &IID_IMFRateSupport))
1978 *obj = &session->IMFRateSupport_iface;
1980 else if (IsEqualIID(riid, &IID_IMFRateControl))
1982 *obj = &session->IMFRateControl_iface;
1984 else
1985 hr = E_NOINTERFACE;
1987 if (*obj)
1988 IUnknown_AddRef((IUnknown *)*obj);
1990 else if (IsEqualGUID(service, &MF_LOCAL_MFT_REGISTRATION_SERVICE))
1992 hr = IMFLocalMFTRegistration_QueryInterface(&local_mft_registration, riid, obj);
1994 else if (IsEqualGUID(service, &MF_TOPONODE_ATTRIBUTE_EDITOR_SERVICE))
1996 *obj = &session->IMFTopologyNodeAttributeEditor_iface;
1997 IUnknown_AddRef((IUnknown *)*obj);
1999 else if (IsEqualGUID(service, &MR_VIDEO_RENDER_SERVICE))
2001 hr = session_get_video_render_service(session, service, riid, obj);
2003 else
2004 FIXME("Unsupported service %s.\n", debugstr_guid(service));
2006 LeaveCriticalSection(&session->cs);
2008 return hr;
2011 static const IMFGetServiceVtbl session_get_service_vtbl =
2013 session_get_service_QueryInterface,
2014 session_get_service_AddRef,
2015 session_get_service_Release,
2016 session_get_service_GetService,
2019 static HRESULT WINAPI session_commands_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
2021 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
2022 IsEqualIID(riid, &IID_IUnknown))
2024 *obj = iface;
2025 IMFAsyncCallback_AddRef(iface);
2026 return S_OK;
2029 WARN("Unsupported %s.\n", debugstr_guid(riid));
2030 *obj = NULL;
2031 return E_NOINTERFACE;
2034 static ULONG WINAPI session_commands_callback_AddRef(IMFAsyncCallback *iface)
2036 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2037 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2040 static ULONG WINAPI session_commands_callback_Release(IMFAsyncCallback *iface)
2042 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2043 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2046 static HRESULT WINAPI session_commands_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
2048 return E_NOTIMPL;
2051 static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
2053 struct session_op *op = impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result));
2054 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2055 struct topo_node *topo_node;
2056 IMFTopologyNode *upstream_node;
2057 unsigned int upstream_output;
2059 EnterCriticalSection(&session->cs);
2061 switch (op->command)
2063 case SESSION_CMD_CLEAR_TOPOLOGIES:
2064 session_clear_topologies(session);
2065 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologiesCleared, &GUID_NULL,
2066 S_OK, NULL);
2067 session_command_complete(session);
2068 break;
2069 case SESSION_CMD_SET_TOPOLOGY:
2070 session_set_topology(session, op->u.set_topology.flags, op->u.set_topology.topology);
2071 session_command_complete(session);
2072 break;
2073 case SESSION_CMD_START:
2074 session_start(session, &op->u.start.time_format, &op->u.start.start_position);
2075 break;
2076 case SESSION_CMD_PAUSE:
2077 session_pause(session);
2078 break;
2079 case SESSION_CMD_STOP:
2080 session_stop(session);
2081 break;
2082 case SESSION_CMD_CLOSE:
2083 session_close(session);
2084 break;
2085 case SESSION_CMD_QM_NOTIFY_TOPOLOGY:
2086 IMFQualityManager_NotifyTopology(session->quality_manager, op->u.notify_topology.topology);
2087 session_command_complete(session);
2088 break;
2089 case SESSION_CMD_SA_READY:
2090 topo_node = session_get_node_by_id(session, op->u.sa_ready.node_id);
2092 if (topo_node->u.sink.requests)
2094 if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node->node, 0, &upstream_node, &upstream_output)))
2096 session_request_sample_from_node(session, upstream_node, upstream_output);
2097 IMFTopologyNode_Release(upstream_node);
2100 break;
2101 default:
2105 LeaveCriticalSection(&session->cs);
2107 return S_OK;
2110 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl =
2112 session_commands_callback_QueryInterface,
2113 session_commands_callback_AddRef,
2114 session_commands_callback_Release,
2115 session_commands_callback_GetParameters,
2116 session_commands_callback_Invoke,
2119 static HRESULT WINAPI session_events_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
2121 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
2122 IsEqualIID(riid, &IID_IUnknown))
2124 *obj = iface;
2125 IMFAsyncCallback_AddRef(iface);
2126 return S_OK;
2129 WARN("Unsupported %s.\n", debugstr_guid(riid));
2130 *obj = NULL;
2131 return E_NOINTERFACE;
2134 static ULONG WINAPI session_events_callback_AddRef(IMFAsyncCallback *iface)
2136 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
2137 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2140 static ULONG WINAPI session_events_callback_Release(IMFAsyncCallback *iface)
2142 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
2143 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2146 static HRESULT WINAPI session_events_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
2148 return E_NOTIMPL;
2151 static HRESULT session_add_media_stream(struct media_session *session, IMFMediaSource *source, IMFMediaStream *stream)
2153 struct topo_node *node;
2154 IMFStreamDescriptor *sd;
2155 DWORD stream_id = 0;
2156 HRESULT hr;
2158 if (FAILED(hr = IMFMediaStream_GetStreamDescriptor(stream, &sd)))
2159 return hr;
2161 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &stream_id);
2162 IMFStreamDescriptor_Release(sd);
2163 if (FAILED(hr))
2164 return hr;
2166 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2168 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->u.source.source == source
2169 && node->u.source.stream_id == stream_id)
2171 if (node->object.source_stream)
2173 WARN("Node already has stream set.\n");
2174 return S_FALSE;
2177 node->object.source_stream = stream;
2178 IMFMediaStream_AddRef(node->object.source_stream);
2179 break;
2183 return S_OK;
2186 static BOOL session_is_source_nodes_state(struct media_session *session, enum object_state state)
2188 struct media_source *source;
2189 struct topo_node *node;
2191 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2193 if (source->state != state)
2194 return FALSE;
2197 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2199 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->state != state)
2200 return FALSE;
2203 return TRUE;
2206 static BOOL session_is_output_nodes_state(struct media_session *session, enum object_state state)
2208 struct topo_node *node;
2210 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2212 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->state != state)
2213 return FALSE;
2216 return TRUE;
2219 static enum object_state session_get_object_state_for_event(MediaEventType event)
2221 switch (event)
2223 case MESourceStarted:
2224 case MEStreamStarted:
2225 case MEStreamSinkStarted:
2226 return OBJ_STATE_STARTED;
2227 case MESourcePaused:
2228 case MEStreamPaused:
2229 case MEStreamSinkPaused:
2230 return OBJ_STATE_PAUSED;
2231 case MESourceStopped:
2232 case MEStreamStopped:
2233 case MEStreamSinkStopped:
2234 return OBJ_STATE_STOPPED;
2235 case MEStreamSinkPrerolled:
2236 return OBJ_STATE_PREROLLED;
2237 default:
2238 return OBJ_STATE_INVALID;
2242 static void session_set_consumed_clock(IUnknown *object, IMFPresentationClock *clock)
2244 IMFClockConsumer *consumer;
2246 if (SUCCEEDED(IUnknown_QueryInterface(object, &IID_IMFClockConsumer, (void **)&consumer)))
2248 IMFClockConsumer_SetPresentationClock(consumer, clock);
2249 IMFClockConsumer_Release(consumer);
2253 static void session_set_presentation_clock(struct media_session *session)
2255 IMFPresentationTimeSource *time_source = NULL;
2256 struct media_source *source;
2257 struct media_sink *sink;
2258 struct topo_node *node;
2259 HRESULT hr;
2261 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2263 if (node->type == MF_TOPOLOGY_TRANSFORM_NODE)
2264 IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
2267 if (!(session->presentation.flags & SESSION_FLAG_PRESENTATION_CLOCK_SET))
2269 /* Attempt to get time source from the sinks. */
2270 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2272 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink->sink, &IID_IMFPresentationTimeSource,
2273 (void **)&time_source)))
2274 break;
2277 if (time_source)
2279 hr = IMFPresentationClock_SetTimeSource(session->clock, time_source);
2280 IMFPresentationTimeSource_Release(time_source);
2282 else
2283 hr = IMFPresentationClock_SetTimeSource(session->clock, session->system_time_source);
2285 if (FAILED(hr))
2286 WARN("Failed to set time source, hr %#x.\n", hr);
2288 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2290 if (node->type != MF_TOPOLOGY_OUTPUT_NODE)
2291 continue;
2293 if (FAILED(hr = IMFStreamSink_BeginGetEvent(node->object.sink_stream, &session->events_callback,
2294 node->object.object)))
2296 WARN("Failed to subscribe to stream sink events, hr %#x.\n", hr);
2300 /* Set clock for all topology nodes. */
2301 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2303 session_set_consumed_clock((IUnknown *)source->source, session->clock);
2306 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2308 if (sink->event_generator && FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(sink->event_generator,
2309 &session->events_callback, (IUnknown *)sink->event_generator)))
2311 WARN("Failed to subscribe to sink events, hr %#x.\n", hr);
2314 if (FAILED(hr = IMFMediaSink_SetPresentationClock(sink->sink, session->clock)))
2315 WARN("Failed to set presentation clock for the sink, hr %#x.\n", hr);
2318 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2320 if (node->type != MF_TOPOLOGY_TRANSFORM_NODE)
2321 continue;
2323 session_set_consumed_clock(node->object.object, session->clock);
2326 session->presentation.flags |= SESSION_FLAG_PRESENTATION_CLOCK_SET;
2330 static HRESULT session_start_clock(struct media_session *session)
2332 LONGLONG start_offset = 0;
2333 HRESULT hr;
2335 if (IsEqualGUID(&session->presentation.time_format, &GUID_NULL))
2337 if (session->presentation.start_position.vt == VT_EMPTY)
2338 start_offset = PRESENTATION_CURRENT_POSITION;
2339 else if (session->presentation.start_position.vt == VT_I8)
2340 start_offset = session->presentation.start_position.hVal.QuadPart;
2341 else
2342 FIXME("Unhandled position type %d.\n", session->presentation.start_position.vt);
2344 else
2345 FIXME("Unhandled time format %s.\n", debugstr_guid(&session->presentation.time_format));
2347 if (FAILED(hr = IMFPresentationClock_Start(session->clock, start_offset)))
2348 WARN("Failed to start session clock, hr %#x.\n", hr);
2350 return hr;
2353 static struct topo_node *session_get_node_object(struct media_session *session, IUnknown *object,
2354 MF_TOPOLOGY_TYPE node_type)
2356 struct topo_node *node = NULL;
2358 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2360 if (node->type == node_type && object == node->object.object)
2361 break;
2364 return node;
2367 static BOOL session_set_node_object_state(struct media_session *session, IUnknown *object,
2368 MF_TOPOLOGY_TYPE node_type, enum object_state state)
2370 struct topo_node *node;
2371 BOOL changed = FALSE;
2373 if ((node = session_get_node_object(session, object, node_type)))
2375 changed = node->state != state;
2376 node->state = state;
2379 return changed;
2382 static void session_set_source_object_state(struct media_session *session, IUnknown *object,
2383 MediaEventType event_type)
2385 IMFStreamSink *stream_sink;
2386 struct media_source *src;
2387 struct media_sink *sink;
2388 enum object_state state;
2389 struct topo_node *node;
2390 unsigned int i, count;
2391 BOOL changed = FALSE;
2392 HRESULT hr;
2394 if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
2395 return;
2397 switch (event_type)
2399 case MESourceStarted:
2400 case MESourcePaused:
2401 case MESourceStopped:
2403 LIST_FOR_EACH_ENTRY(src, &session->presentation.sources, struct media_source, entry)
2405 if (object == (IUnknown *)src->source)
2407 changed = src->state != state;
2408 src->state = state;
2409 break;
2412 break;
2413 case MEStreamStarted:
2414 case MEStreamPaused:
2415 case MEStreamStopped:
2417 changed = session_set_node_object_state(session, object, MF_TOPOLOGY_SOURCESTREAM_NODE, state);
2418 default:
2422 if (!changed)
2423 return;
2425 switch (session->state)
2427 case SESSION_STATE_STARTING_SOURCES:
2428 if (!session_is_source_nodes_state(session, OBJ_STATE_STARTED))
2429 break;
2431 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_STARTED_SOURCE);
2433 session_set_presentation_clock(session);
2435 if (session->presentation.flags & SESSION_FLAG_NEEDS_PREROLL)
2437 MFTIME preroll_time = 0;
2439 if (session->presentation.start_position.vt == VT_I8)
2440 preroll_time = session->presentation.start_position.hVal.QuadPart;
2442 /* Mark stream sinks without prerolling support as PREROLLED to keep state test logic generic. */
2443 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2445 if (sink->preroll)
2447 /* FIXME: abort and enter error state on failure. */
2448 if (FAILED(hr = IMFMediaSinkPreroll_NotifyPreroll(sink->preroll, preroll_time)))
2449 WARN("Preroll notification failed, hr %#x.\n", hr);
2451 else
2453 if (SUCCEEDED(IMFMediaSink_GetStreamSinkCount(sink->sink, &count)))
2455 for (i = 0; i < count; ++i)
2457 if (SUCCEEDED(IMFMediaSink_GetStreamSinkByIndex(sink->sink, i, &stream_sink)))
2459 session_set_node_object_state(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE,
2460 OBJ_STATE_PREROLLED);
2461 IMFStreamSink_Release(stream_sink);
2467 session->state = SESSION_STATE_PREROLLING_SINKS;
2469 else if (SUCCEEDED(session_start_clock(session)))
2470 session->state = SESSION_STATE_STARTING_SINKS;
2472 break;
2473 case SESSION_STATE_PAUSING_SOURCES:
2474 if (!session_is_source_nodes_state(session, OBJ_STATE_PAUSED))
2475 break;
2477 session_set_paused(session, S_OK);
2478 break;
2479 case SESSION_STATE_STOPPING_SOURCES:
2480 if (!session_is_source_nodes_state(session, OBJ_STATE_STOPPED))
2481 break;
2483 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2485 switch (node->type)
2487 case MF_TOPOLOGY_OUTPUT_NODE:
2488 IMFStreamSink_Flush(node->object.sink_stream);
2489 break;
2490 case MF_TOPOLOGY_TRANSFORM_NODE:
2491 IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_COMMAND_FLUSH, 0);
2492 break;
2493 default:
2498 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
2500 if (session->presentation.flags & SESSION_FLAG_FINALIZE_SINKS)
2501 session_finalize_sinks(session);
2502 else
2503 session_set_stopped(session, S_OK);
2505 break;
2506 default:
2511 static void session_set_sink_stream_state(struct media_session *session, IMFStreamSink *stream,
2512 MediaEventType event_type)
2514 struct media_source *source;
2515 enum object_state state;
2516 HRESULT hr = S_OK;
2517 BOOL changed;
2519 if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
2520 return;
2522 if (!(changed = session_set_node_object_state(session, (IUnknown *)stream, MF_TOPOLOGY_OUTPUT_NODE, state)))
2523 return;
2525 switch (session->state)
2527 case SESSION_STATE_PREROLLING_SINKS:
2528 if (!session_is_output_nodes_state(session, OBJ_STATE_PREROLLED))
2529 break;
2531 if (SUCCEEDED(session_start_clock(session)))
2532 session->state = SESSION_STATE_STARTING_SINKS;
2533 break;
2534 case SESSION_STATE_STARTING_SINKS:
2535 if (!session_is_output_nodes_state(session, OBJ_STATE_STARTED))
2536 break;
2538 session_set_started(session);
2539 break;
2540 case SESSION_STATE_PAUSING_SINKS:
2541 if (!session_is_output_nodes_state(session, OBJ_STATE_PAUSED))
2542 break;
2544 session->state = SESSION_STATE_PAUSING_SOURCES;
2546 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2548 if (FAILED(hr = IMFMediaSource_Pause(source->source)))
2549 break;
2552 if (FAILED(hr))
2553 session_set_paused(session, hr);
2555 break;
2556 case SESSION_STATE_STOPPING_SINKS:
2557 if (!session_is_output_nodes_state(session, OBJ_STATE_STOPPED))
2558 break;
2560 session->state = SESSION_STATE_STOPPING_SOURCES;
2562 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2564 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION)
2565 IMFMediaSource_Stop(source->source);
2566 else if (FAILED(hr = IMFMediaSource_Stop(source->source)))
2567 break;
2570 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION || FAILED(hr))
2571 session_set_stopped(session, hr);
2573 break;
2574 default:
2579 static struct sample *transform_create_sample(IMFSample *sample)
2581 struct sample *sample_entry = heap_alloc_zero(sizeof(*sample_entry));
2583 if (sample_entry)
2585 sample_entry->sample = sample;
2586 if (sample_entry->sample)
2587 IMFSample_AddRef(sample_entry->sample);
2590 return sample_entry;
2593 static HRESULT transform_get_external_output_sample(const struct media_session *session, struct topo_node *transform,
2594 unsigned int output_index, const MFT_OUTPUT_STREAM_INFO *stream_info, IMFSample **sample)
2596 unsigned int buffer_size, downstream_input;
2597 IMFTopologyNode *downstream_node;
2598 IMFMediaBuffer *buffer = NULL;
2599 struct topo_node *topo_node;
2600 TOPOID node_id;
2601 HRESULT hr;
2603 if (FAILED(IMFTopologyNode_GetOutput(transform->node, output_index, &downstream_node, &downstream_input)))
2605 WARN("Failed to get connected node for output %u.\n", output_index);
2606 return MF_E_UNEXPECTED;
2609 IMFTopologyNode_GetTopoNodeID(downstream_node, &node_id);
2610 IMFTopologyNode_Release(downstream_node);
2612 topo_node = session_get_node_by_id(session, node_id);
2614 if (topo_node->type == MF_TOPOLOGY_OUTPUT_NODE && topo_node->u.sink.allocator)
2616 hr = IMFVideoSampleAllocator_AllocateSample(topo_node->u.sink.allocator, sample);
2618 else
2620 buffer_size = max(stream_info->cbSize, transform->u.transform.outputs[output_index].min_buffer_size);
2622 hr = MFCreateAlignedMemoryBuffer(buffer_size, stream_info->cbAlignment, &buffer);
2623 if (SUCCEEDED(hr))
2624 hr = MFCreateSample(sample);
2626 if (SUCCEEDED(hr))
2627 hr = IMFSample_AddBuffer(*sample, buffer);
2629 if (buffer)
2630 IMFMediaBuffer_Release(buffer);
2633 return hr;
2636 static HRESULT transform_node_pull_samples(const struct media_session *session, struct topo_node *node)
2638 MFT_OUTPUT_STREAM_INFO stream_info;
2639 MFT_OUTPUT_DATA_BUFFER *buffers;
2640 struct sample *queued_sample;
2641 DWORD status = 0;
2642 unsigned int i;
2643 HRESULT hr = E_UNEXPECTED;
2645 if (!(buffers = heap_calloc(node->u.transform.output_count, sizeof(*buffers))))
2646 return E_OUTOFMEMORY;
2648 for (i = 0; i < node->u.transform.output_count; ++i)
2650 buffers[i].dwStreamID = transform_node_get_stream_id(node, TRUE, i);
2651 buffers[i].pSample = NULL;
2652 buffers[i].dwStatus = 0;
2653 buffers[i].pEvents = NULL;
2655 memset(&stream_info, 0, sizeof(stream_info));
2656 if (FAILED(hr = IMFTransform_GetOutputStreamInfo(node->object.transform, buffers[i].dwStreamID, &stream_info)))
2657 break;
2659 if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)))
2661 if (FAILED(hr = transform_get_external_output_sample(session, node, i, &stream_info, &buffers[i].pSample)))
2662 break;
2666 if (SUCCEEDED(hr))
2667 hr = IMFTransform_ProcessOutput(node->object.transform, 0, node->u.transform.output_count, buffers, &status);
2669 /* Collect returned samples for all streams. */
2670 for (i = 0; i < node->u.transform.output_count; ++i)
2672 if (buffers[i].pEvents)
2673 IMFCollection_Release(buffers[i].pEvents);
2675 if (SUCCEEDED(hr) && !(buffers[i].dwStatus & MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE))
2677 if (session->quality_manager)
2678 IMFQualityManager_NotifyProcessOutput(session->quality_manager, node->node, i, buffers[i].pSample);
2680 queued_sample = transform_create_sample(buffers[i].pSample);
2681 list_add_tail(&node->u.transform.outputs[i].samples, &queued_sample->entry);
2684 if (buffers[i].pSample)
2685 IMFSample_Release(buffers[i].pSample);
2688 heap_free(buffers);
2690 return hr;
2693 static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input,
2694 IMFSample *sample)
2696 struct sample *sample_entry, *sample_entry2;
2697 DWORD stream_id, downstream_input;
2698 IMFTopologyNode *downstream_node;
2699 struct topo_node *topo_node;
2700 MF_TOPOLOGY_TYPE node_type;
2701 BOOL drain = FALSE;
2702 TOPOID node_id;
2703 unsigned int i;
2704 HRESULT hr;
2706 if (session->quality_manager)
2707 IMFQualityManager_NotifyProcessInput(session->quality_manager, node, input, sample);
2709 IMFTopologyNode_GetNodeType(node, &node_type);
2710 IMFTopologyNode_GetTopoNodeID(node, &node_id);
2712 topo_node = session_get_node_by_id(session, node_id);
2714 switch (node_type)
2716 case MF_TOPOLOGY_OUTPUT_NODE:
2717 if (sample)
2719 if (topo_node->u.sink.requests)
2721 if (FAILED(hr = IMFStreamSink_ProcessSample(topo_node->object.sink_stream, sample)))
2722 WARN("Stream sink failed to process sample, hr %#x.\n", hr);
2723 topo_node->u.sink.requests--;
2726 else if (FAILED(hr = IMFStreamSink_PlaceMarker(topo_node->object.sink_stream, MFSTREAMSINK_MARKER_ENDOFSEGMENT,
2727 NULL, NULL)))
2729 WARN("Failed to place sink marker, hr %#x.\n", hr);
2731 break;
2732 case MF_TOPOLOGY_TRANSFORM_NODE:
2734 transform_node_pull_samples(session, topo_node);
2736 sample_entry = transform_create_sample(sample);
2737 list_add_tail(&topo_node->u.transform.inputs[input].samples, &sample_entry->entry);
2739 for (i = 0; i < topo_node->u.transform.input_count; ++i)
2741 stream_id = transform_node_get_stream_id(topo_node, FALSE, i);
2742 LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.inputs[i].samples,
2743 struct sample, entry)
2745 if (sample_entry->sample)
2747 if ((hr = IMFTransform_ProcessInput(topo_node->object.transform, stream_id,
2748 sample_entry->sample, 0)) == MF_E_NOTACCEPTING)
2749 break;
2750 if (FAILED(hr))
2751 WARN("Failed to process input for stream %u/%u, hr %#x.\n", i, stream_id, hr);
2752 transform_release_sample(sample_entry);
2754 else
2756 transform_stream_drop_samples(&topo_node->u.transform.inputs[i]);
2757 drain = TRUE;
2762 if (drain)
2764 if (FAILED(hr = IMFTransform_ProcessMessage(topo_node->object.transform, MFT_MESSAGE_COMMAND_DRAIN, 0)))
2765 WARN("Drain command failed for transform, hr %#x.\n", hr);
2768 transform_node_pull_samples(session, topo_node);
2770 /* Remaining unprocessed input has been discarded, now queue markers for every output. */
2771 if (drain)
2773 for (i = 0; i < topo_node->u.transform.output_count; ++i)
2775 if ((sample_entry = transform_create_sample(NULL)))
2776 list_add_tail(&topo_node->u.transform.outputs[i].samples, &sample_entry->entry);
2780 /* Push down all available output. */
2781 for (i = 0; i < topo_node->u.transform.output_count; ++i)
2783 if (FAILED(IMFTopologyNode_GetOutput(node, i, &downstream_node, &downstream_input)))
2785 WARN("Failed to get connected node for output %u.\n", i);
2786 continue;
2789 LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.outputs[i].samples,
2790 struct sample, entry)
2792 if (!topo_node->u.transform.outputs[i].requests)
2793 break;
2795 session_deliver_sample_to_node(session, downstream_node, downstream_input, sample_entry->sample);
2796 topo_node->u.transform.outputs[i].requests--;
2798 transform_release_sample(sample_entry);
2801 IMFTopologyNode_Release(downstream_node);
2804 break;
2805 case MF_TOPOLOGY_TEE_NODE:
2806 FIXME("Unhandled downstream node type %d.\n", node_type);
2807 break;
2808 default:
2813 static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output)
2815 IMFTopologyNode *downstream_node, *upstream_node;
2816 unsigned int downstream_input, upstream_output;
2817 struct topo_node *topo_node;
2818 MF_TOPOLOGY_TYPE node_type;
2819 struct sample *sample;
2820 TOPOID node_id;
2821 HRESULT hr;
2823 IMFTopologyNode_GetNodeType(node, &node_type);
2824 IMFTopologyNode_GetTopoNodeID(node, &node_id);
2826 topo_node = session_get_node_by_id(session, node_id);
2828 switch (node_type)
2830 case MF_TOPOLOGY_SOURCESTREAM_NODE:
2831 if (FAILED(hr = IMFMediaStream_RequestSample(topo_node->object.source_stream, NULL)))
2832 WARN("Sample request failed, hr %#x.\n", hr);
2833 break;
2834 case MF_TOPOLOGY_TRANSFORM_NODE:
2836 if (list_empty(&topo_node->u.transform.outputs[output].samples))
2838 /* Forward request to upstream node. */
2839 if (SUCCEEDED(hr = IMFTopologyNode_GetInput(node, 0 /* FIXME */, &upstream_node, &upstream_output)))
2841 if (SUCCEEDED(hr = session_request_sample_from_node(session, upstream_node, upstream_output)))
2842 topo_node->u.transform.outputs[output].requests++;
2843 IMFTopologyNode_Release(upstream_node);
2846 else
2848 if (SUCCEEDED(hr = IMFTopologyNode_GetOutput(node, output, &downstream_node, &downstream_input)))
2850 sample = LIST_ENTRY(list_head(&topo_node->u.transform.outputs[output].samples), struct sample, entry);
2851 session_deliver_sample_to_node(session, downstream_node, downstream_input, sample->sample);
2852 transform_release_sample(sample);
2853 IMFTopologyNode_Release(downstream_node);
2857 break;
2858 case MF_TOPOLOGY_TEE_NODE:
2859 FIXME("Unhandled upstream node type %d.\n", node_type);
2860 default:
2861 hr = E_UNEXPECTED;
2864 return hr;
2867 static void session_request_sample(struct media_session *session, IMFStreamSink *sink_stream)
2869 struct topo_node *sink_node = NULL, *node;
2870 IMFTopologyNode *upstream_node;
2871 DWORD upstream_output;
2872 HRESULT hr;
2874 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2876 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink_stream)
2878 sink_node = node;
2879 break;
2883 if (!sink_node)
2884 return;
2886 if (FAILED(hr = IMFTopologyNode_GetInput(sink_node->node, 0, &upstream_node, &upstream_output)))
2888 WARN("Failed to get upstream node connection, hr %#x.\n", hr);
2889 return;
2892 if (SUCCEEDED(session_request_sample_from_node(session, upstream_node, upstream_output)))
2893 sink_node->u.sink.requests++;
2894 IMFTopologyNode_Release(upstream_node);
2897 static void session_deliver_sample(struct media_session *session, IMFMediaStream *stream, const PROPVARIANT *value)
2899 struct topo_node *source_node = NULL, *node;
2900 IMFTopologyNode *downstream_node;
2901 DWORD downstream_input;
2902 HRESULT hr;
2904 if (value && (value->vt != VT_UNKNOWN || !value->punkVal))
2906 WARN("Unexpected value type %d.\n", value->vt);
2907 return;
2910 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2912 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->object.source_stream == stream)
2914 source_node = node;
2915 break;
2919 if (!source_node)
2920 return;
2922 if (!value)
2923 source_node->flags |= TOPO_NODE_END_OF_STREAM;
2925 if (FAILED(hr = IMFTopologyNode_GetOutput(source_node->node, 0, &downstream_node, &downstream_input)))
2927 WARN("Failed to get downstream node connection, hr %#x.\n", hr);
2928 return;
2931 session_deliver_sample_to_node(session, downstream_node, downstream_input, value ? (IMFSample *)value->punkVal : NULL);
2932 IMFTopologyNode_Release(downstream_node);
2935 static void session_sink_invalidated(struct media_session *session, IMFMediaEvent *event, IMFStreamSink *sink)
2937 struct topo_node *node, *sink_node = NULL;
2938 HRESULT hr;
2940 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2942 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink)
2944 sink_node = node;
2945 break;
2949 if (!sink_node)
2950 return;
2952 if (!event)
2954 if (FAILED(hr = MFCreateMediaEvent(MESinkInvalidated, &GUID_NULL, S_OK, NULL, &event)))
2955 WARN("Failed to create event, hr %#x.\n", hr);
2958 if (!event)
2959 return;
2961 IMFMediaEvent_SetUINT64(event, &MF_EVENT_OUTPUT_NODE, sink_node->node_id);
2962 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
2964 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED);
2967 static BOOL session_nodes_is_mask_set(struct media_session *session, MF_TOPOLOGY_TYPE node_type, unsigned int flags)
2969 struct media_source *source;
2970 struct topo_node *node;
2972 if (node_type == MF_TOPOLOGY_MAX)
2974 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2976 if ((source->flags & flags) != flags)
2977 return FALSE;
2980 else
2982 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2984 if (node->type == node_type && (node->flags & flags) != flags)
2985 return FALSE;
2989 return TRUE;
2992 static void session_raise_end_of_presentation(struct media_session *session)
2994 if (!(session_nodes_is_mask_set(session, MF_TOPOLOGY_SOURCESTREAM_NODE, TOPO_NODE_END_OF_STREAM)))
2995 return;
2997 if (!(session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION))
2999 if (session_nodes_is_mask_set(session, MF_TOPOLOGY_MAX, SOURCE_FLAG_END_OF_PRESENTATION))
3001 session->presentation.flags |= SESSION_FLAG_END_OF_PRESENTATION;
3002 session_push_back_command(session, SESSION_CMD_END);
3003 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, NULL);
3008 static void session_handle_end_of_stream(struct media_session *session, IMFMediaStream *stream)
3010 struct topo_node *node;
3012 if (!(node = session_get_node_object(session, (IUnknown *)stream, MF_TOPOLOGY_SOURCESTREAM_NODE))
3013 || node->flags & TOPO_NODE_END_OF_STREAM)
3015 return;
3018 session_deliver_sample(session, stream, NULL);
3020 session_raise_end_of_presentation(session);
3023 static void session_handle_end_of_presentation(struct media_session *session, IMFMediaSource *object)
3025 struct media_source *source;
3027 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3029 if (source->source == object)
3031 if (!(source->flags & SOURCE_FLAG_END_OF_PRESENTATION))
3033 source->flags |= SOURCE_FLAG_END_OF_PRESENTATION;
3034 session_raise_end_of_presentation(session);
3037 break;
3042 static void session_sink_stream_marker(struct media_session *session, IMFStreamSink *stream_sink)
3044 struct topo_node *node;
3046 if (!(node = session_get_node_object(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE))
3047 || node->flags & TOPO_NODE_END_OF_STREAM)
3049 return;
3052 node->flags |= TOPO_NODE_END_OF_STREAM;
3054 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION &&
3055 session_nodes_is_mask_set(session, MF_TOPOLOGY_OUTPUT_NODE, TOPO_NODE_END_OF_STREAM))
3057 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED);
3058 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
3059 session_stop(session);
3063 static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
3065 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
3066 IMFMediaEventGenerator *event_source;
3067 IMFMediaEvent *event = NULL;
3068 MediaEventType event_type;
3069 IUnknown *object = NULL;
3070 IMFMediaSource *source;
3071 IMFMediaStream *stream;
3072 PROPVARIANT value;
3073 HRESULT hr;
3075 if (FAILED(hr = IMFAsyncResult_GetState(result, (IUnknown **)&event_source)))
3076 return hr;
3078 if (FAILED(hr = IMFMediaEventGenerator_EndGetEvent(event_source, result, &event)))
3080 WARN("Failed to get event from %p, hr %#x.\n", event_source, hr);
3081 goto failed;
3084 if (FAILED(hr = IMFMediaEvent_GetType(event, &event_type)))
3086 WARN("Failed to get event type, hr %#x.\n", hr);
3087 goto failed;
3090 value.vt = VT_EMPTY;
3091 if (FAILED(hr = IMFMediaEvent_GetValue(event, &value)))
3093 WARN("Failed to get event value, hr %#x.\n", hr);
3094 goto failed;
3097 switch (event_type)
3099 case MESourceStarted:
3100 case MESourcePaused:
3101 case MESourceStopped:
3102 case MEStreamStarted:
3103 case MEStreamPaused:
3104 case MEStreamStopped:
3106 EnterCriticalSection(&session->cs);
3107 session_set_source_object_state(session, (IUnknown *)event_source, event_type);
3108 LeaveCriticalSection(&session->cs);
3110 break;
3112 case MEBufferingStarted:
3113 case MEBufferingStopped:
3115 EnterCriticalSection(&session->cs);
3116 if (session_get_media_source(session, (IMFMediaSource *)event_source))
3118 if (event_type == MEBufferingStarted)
3119 IMFPresentationClock_Pause(session->clock);
3120 else
3121 IMFPresentationClock_Start(session->clock, PRESENTATION_CURRENT_POSITION);
3123 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3125 LeaveCriticalSection(&session->cs);
3126 break;
3128 case MEReconnectStart:
3129 case MEReconnectEnd:
3131 EnterCriticalSection(&session->cs);
3132 if (session_get_media_source(session, (IMFMediaSource *)event_source))
3133 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3134 LeaveCriticalSection(&session->cs);
3135 break;
3137 case MEExtendedType:
3138 case MERendererEvent:
3139 case MEStreamSinkFormatChanged:
3141 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3142 break;
3144 case MENewStream:
3145 stream = (IMFMediaStream *)value.punkVal;
3147 if (value.vt != VT_UNKNOWN || !stream)
3149 WARN("Unexpected event value.\n");
3150 break;
3153 if (FAILED(hr = IMFMediaStream_GetMediaSource(stream, &source)))
3154 break;
3156 EnterCriticalSection(&session->cs);
3157 if (SUCCEEDED(hr = session_add_media_stream(session, source, stream)))
3158 hr = IMFMediaStream_BeginGetEvent(stream, &session->events_callback, (IUnknown *)stream);
3159 LeaveCriticalSection(&session->cs);
3161 IMFMediaSource_Release(source);
3163 break;
3164 case MEStreamSinkStarted:
3165 case MEStreamSinkPaused:
3166 case MEStreamSinkStopped:
3167 case MEStreamSinkPrerolled:
3169 EnterCriticalSection(&session->cs);
3170 session_set_sink_stream_state(session, (IMFStreamSink *)event_source, event_type);
3171 LeaveCriticalSection(&session->cs);
3173 break;
3174 case MEStreamSinkMarker:
3176 EnterCriticalSection(&session->cs);
3177 session_sink_stream_marker(session, (IMFStreamSink *)event_source);
3178 LeaveCriticalSection(&session->cs);
3180 break;
3181 case MEStreamSinkRequestSample:
3183 EnterCriticalSection(&session->cs);
3184 session_request_sample(session, (IMFStreamSink *)event_source);
3185 LeaveCriticalSection(&session->cs);
3187 break;
3188 case MEMediaSample:
3190 EnterCriticalSection(&session->cs);
3191 session_deliver_sample(session, (IMFMediaStream *)event_source, &value);
3192 LeaveCriticalSection(&session->cs);
3194 break;
3195 case MEEndOfStream:
3197 EnterCriticalSection(&session->cs);
3198 session_handle_end_of_stream(session, (IMFMediaStream *)event_source);
3199 LeaveCriticalSection(&session->cs);
3201 break;
3203 case MEEndOfPresentation:
3205 EnterCriticalSection(&session->cs);
3206 session_handle_end_of_presentation(session, (IMFMediaSource *)event_source);
3207 LeaveCriticalSection(&session->cs);
3209 break;
3210 case MEAudioSessionGroupingParamChanged:
3211 case MEAudioSessionIconChanged:
3212 case MEAudioSessionNameChanged:
3213 case MEAudioSessionVolumeChanged:
3215 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3217 break;
3218 case MEAudioSessionDeviceRemoved:
3219 case MEAudioSessionDisconnected:
3220 case MEAudioSessionExclusiveModeOverride:
3221 case MEAudioSessionFormatChanged:
3222 case MEAudioSessionServerShutdown:
3224 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3225 /* fallthrough */
3226 case MESinkInvalidated:
3228 EnterCriticalSection(&session->cs);
3229 session_sink_invalidated(session, event_type == MESinkInvalidated ? event : NULL,
3230 (IMFStreamSink *)event_source);
3231 LeaveCriticalSection(&session->cs);
3233 break;
3234 case MEQualityNotify:
3236 if (session->quality_manager)
3238 if (FAILED(IMFMediaEventGenerator_QueryInterface(event_source, &IID_IMFStreamSink, (void **)&object)))
3239 IMFMediaEventGenerator_QueryInterface(event_source, &IID_IMFTransform, (void **)&object);
3241 if (object)
3243 IMFQualityManager_NotifyQualityEvent(session->quality_manager, object, event);
3244 IUnknown_Release(object);
3248 break;
3249 default:
3253 PropVariantClear(&value);
3255 failed:
3256 if (event)
3257 IMFMediaEvent_Release(event);
3259 if (FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(event_source, iface, (IUnknown *)event_source)))
3260 WARN("Failed to re-subscribe, hr %#x.\n", hr);
3262 IMFMediaEventGenerator_Release(event_source);
3264 return hr;
3267 static const IMFAsyncCallbackVtbl session_events_callback_vtbl =
3269 session_events_callback_QueryInterface,
3270 session_events_callback_AddRef,
3271 session_events_callback_Release,
3272 session_events_callback_GetParameters,
3273 session_events_callback_Invoke,
3276 static HRESULT WINAPI session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
3278 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
3279 IsEqualIID(riid, &IID_IUnknown))
3281 *obj = iface;
3282 IMFAsyncCallback_AddRef(iface);
3283 return S_OK;
3286 WARN("Unsupported %s.\n", debugstr_guid(riid));
3287 *obj = NULL;
3288 return E_NOINTERFACE;
3291 static ULONG WINAPI session_sink_finalizer_callback_AddRef(IMFAsyncCallback *iface)
3293 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3294 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3297 static ULONG WINAPI session_sink_finalizer_callback_Release(IMFAsyncCallback *iface)
3299 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3300 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3303 static HRESULT WINAPI session_sink_finalizer_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
3305 return E_NOTIMPL;
3308 static HRESULT WINAPI session_sink_finalizer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
3310 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3311 IMFFinalizableMediaSink *fin_sink = NULL;
3312 BOOL sinks_finalized = TRUE;
3313 struct media_sink *sink;
3314 IUnknown *state;
3315 HRESULT hr;
3317 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
3318 return hr;
3320 EnterCriticalSection(&session->cs);
3322 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
3324 if (state == (IUnknown *)sink->sink)
3326 if (FAILED(hr = IMFMediaSink_QueryInterface(sink->sink, &IID_IMFFinalizableMediaSink, (void **)&fin_sink)))
3327 WARN("Unexpected, missing IMFFinalizableSink, hr %#x.\n", hr);
3329 else
3331 sinks_finalized &= sink->finalized;
3332 if (!sinks_finalized)
3333 break;
3337 IUnknown_Release(state);
3339 if (fin_sink)
3341 /* Complete session transition, or close prematurely on error. */
3342 if (SUCCEEDED(hr = IMFFinalizableMediaSink_EndFinalize(fin_sink, result)))
3344 sink->finalized = TRUE;
3345 if (sinks_finalized)
3346 session_set_closed(session, hr);
3348 IMFFinalizableMediaSink_Release(fin_sink);
3351 LeaveCriticalSection(&session->cs);
3353 return S_OK;
3356 static const IMFAsyncCallbackVtbl session_sink_finalizer_callback_vtbl =
3358 session_sink_finalizer_callback_QueryInterface,
3359 session_sink_finalizer_callback_AddRef,
3360 session_sink_finalizer_callback_Release,
3361 session_sink_finalizer_callback_GetParameters,
3362 session_sink_finalizer_callback_Invoke,
3365 static HRESULT WINAPI session_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
3367 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3368 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
3371 static ULONG WINAPI session_rate_support_AddRef(IMFRateSupport *iface)
3373 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3374 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3377 static ULONG WINAPI session_rate_support_Release(IMFRateSupport *iface)
3379 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3380 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3383 static HRESULT session_presentation_object_get_rate(IUnknown *object, MFRATE_DIRECTION direction,
3384 BOOL thin, BOOL fastest, float *result)
3386 IMFRateSupport *rate_support;
3387 float rate;
3388 HRESULT hr;
3390 /* For objects that don't support rate control, it's assumed that only forward direction is allowed, at 1.0f. */
3392 if (FAILED(hr = MFGetService(object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support)))
3394 if (direction == MFRATE_FORWARD)
3396 *result = 1.0f;
3397 return S_OK;
3399 else
3400 return MF_E_REVERSE_UNSUPPORTED;
3403 rate = 0.0f;
3404 if (fastest)
3406 if (SUCCEEDED(hr = IMFRateSupport_GetFastestRate(rate_support, direction, thin, &rate)))
3407 *result = min(fabsf(rate), *result);
3409 else
3411 if (SUCCEEDED(hr = IMFRateSupport_GetSlowestRate(rate_support, direction, thin, &rate)))
3412 *result = max(fabsf(rate), *result);
3415 IMFRateSupport_Release(rate_support);
3417 return hr;
3420 static HRESULT session_get_presentation_rate(struct media_session *session, MFRATE_DIRECTION direction,
3421 BOOL thin, BOOL fastest, float *result)
3423 struct media_source *source;
3424 struct media_sink *sink;
3425 HRESULT hr = E_POINTER;
3426 float rate;
3428 rate = fastest ? FLT_MAX : 0.0f;
3430 EnterCriticalSection(&session->cs);
3432 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
3434 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3436 if (FAILED(hr = session_presentation_object_get_rate((IUnknown *)source->source, direction, thin, fastest, &rate)))
3437 break;
3440 if (SUCCEEDED(hr))
3442 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
3444 if (FAILED(hr = session_presentation_object_get_rate((IUnknown *)sink->sink, direction, thin, fastest, &rate)))
3445 break;
3450 LeaveCriticalSection(&session->cs);
3452 if (SUCCEEDED(hr))
3453 *result = direction == MFRATE_FORWARD ? rate : -rate;
3455 return hr;
3458 static HRESULT WINAPI session_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
3459 BOOL thin, float *rate)
3461 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3463 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
3465 return session_get_presentation_rate(session, direction, thin, FALSE, rate);
3468 static HRESULT WINAPI session_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
3469 BOOL thin, float *rate)
3471 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3473 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
3475 return session_get_presentation_rate(session, direction, thin, TRUE, rate);
3478 static HRESULT WINAPI session_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
3479 float *nearest_supported_rate)
3481 FIXME("%p, %d, %f, %p.\n", iface, thin, rate, nearest_supported_rate);
3483 return E_NOTIMPL;
3486 static const IMFRateSupportVtbl session_rate_support_vtbl =
3488 session_rate_support_QueryInterface,
3489 session_rate_support_AddRef,
3490 session_rate_support_Release,
3491 session_rate_support_GetSlowestRate,
3492 session_rate_support_GetFastestRate,
3493 session_rate_support_IsRateSupported,
3496 static HRESULT WINAPI session_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj)
3498 struct media_session *session = impl_session_from_IMFRateControl(iface);
3499 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
3502 static ULONG WINAPI session_rate_control_AddRef(IMFRateControl *iface)
3504 struct media_session *session = impl_session_from_IMFRateControl(iface);
3505 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3508 static ULONG WINAPI session_rate_control_Release(IMFRateControl *iface)
3510 struct media_session *session = impl_session_from_IMFRateControl(iface);
3511 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3514 static HRESULT WINAPI session_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate)
3516 FIXME("%p, %d, %f.\n", iface, thin, rate);
3518 return E_NOTIMPL;
3521 static HRESULT WINAPI session_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
3523 struct media_session *session = impl_session_from_IMFRateControl(iface);
3525 TRACE("%p, %p, %p.\n", iface, thin, rate);
3527 return IMFRateControl_GetRate(session->clock_rate_control, thin, rate);
3530 static const IMFRateControlVtbl session_rate_control_vtbl =
3532 session_rate_control_QueryInterface,
3533 session_rate_control_AddRef,
3534 session_rate_control_Release,
3535 session_rate_control_SetRate,
3536 session_rate_control_GetRate,
3539 static HRESULT WINAPI node_attribute_editor_QueryInterface(IMFTopologyNodeAttributeEditor *iface,
3540 REFIID riid, void **obj)
3542 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
3544 if (IsEqualIID(riid, &IID_IMFTopologyNodeAttributeEditor) ||
3545 IsEqualIID(riid, &IID_IUnknown))
3547 *obj = iface;
3548 IMFTopologyNodeAttributeEditor_AddRef(iface);
3549 return S_OK;
3552 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
3553 *obj = NULL;
3554 return E_NOINTERFACE;
3557 static ULONG WINAPI node_attribute_editor_AddRef(IMFTopologyNodeAttributeEditor *iface)
3559 struct media_session *session = impl_session_from_IMFTopologyNodeAttributeEditor(iface);
3560 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3563 static ULONG WINAPI node_attribute_editor_Release(IMFTopologyNodeAttributeEditor *iface)
3565 struct media_session *session = impl_session_from_IMFTopologyNodeAttributeEditor(iface);
3566 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3569 static HRESULT WINAPI node_attribute_editor_UpdateNodeAttributes(IMFTopologyNodeAttributeEditor *iface,
3570 TOPOID id, DWORD count, MFTOPONODE_ATTRIBUTE_UPDATE *updates)
3572 FIXME("%p, %s, %u, %p.\n", iface, wine_dbgstr_longlong(id), count, updates);
3574 return E_NOTIMPL;
3577 static const IMFTopologyNodeAttributeEditorVtbl node_attribute_editor_vtbl =
3579 node_attribute_editor_QueryInterface,
3580 node_attribute_editor_AddRef,
3581 node_attribute_editor_Release,
3582 node_attribute_editor_UpdateNodeAttributes,
3585 /***********************************************************************
3586 * MFCreateMediaSession (mf.@)
3588 HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **session)
3590 BOOL without_quality_manager = FALSE;
3591 struct media_session *object;
3592 HRESULT hr;
3594 TRACE("%p, %p.\n", config, session);
3596 object = heap_alloc_zero(sizeof(*object));
3597 if (!object)
3598 return E_OUTOFMEMORY;
3600 object->IMFMediaSession_iface.lpVtbl = &mfmediasessionvtbl;
3601 object->IMFGetService_iface.lpVtbl = &session_get_service_vtbl;
3602 object->IMFRateSupport_iface.lpVtbl = &session_rate_support_vtbl;
3603 object->IMFRateControl_iface.lpVtbl = &session_rate_control_vtbl;
3604 object->IMFTopologyNodeAttributeEditor_iface.lpVtbl = &node_attribute_editor_vtbl;
3605 object->commands_callback.lpVtbl = &session_commands_callback_vtbl;
3606 object->events_callback.lpVtbl = &session_events_callback_vtbl;
3607 object->sink_finalizer_callback.lpVtbl = &session_sink_finalizer_callback_vtbl;
3608 object->refcount = 1;
3609 list_init(&object->topologies);
3610 list_init(&object->commands);
3611 list_init(&object->presentation.sources);
3612 list_init(&object->presentation.sinks);
3613 list_init(&object->presentation.nodes);
3614 InitializeCriticalSection(&object->cs);
3616 if (FAILED(hr = MFCreateTopology(&object->presentation.current_topology)))
3617 goto failed;
3619 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
3620 goto failed;
3622 if (FAILED(hr = MFCreatePresentationClock(&object->clock)))
3623 goto failed;
3625 if (FAILED(hr = MFCreateSystemTimeSource(&object->system_time_source)))
3626 goto failed;
3628 if (FAILED(hr = IMFPresentationClock_QueryInterface(object->clock, &IID_IMFRateControl,
3629 (void **)&object->clock_rate_control)))
3631 goto failed;
3634 if (config)
3636 GUID clsid;
3638 if (SUCCEEDED(IMFAttributes_GetGUID(config, &MF_SESSION_TOPOLOADER, &clsid)))
3640 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTopoLoader,
3641 (void **)&object->topo_loader)))
3643 WARN("Failed to create custom topology loader, hr %#x.\n", hr);
3647 if (SUCCEEDED(IMFAttributes_GetGUID(config, &MF_SESSION_QUALITY_MANAGER, &clsid)))
3649 if (!(without_quality_manager = IsEqualGUID(&clsid, &GUID_NULL)))
3651 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFQualityManager,
3652 (void **)&object->quality_manager)))
3654 WARN("Failed to create custom quality manager, hr %#x.\n", hr);
3660 if (!object->topo_loader && FAILED(hr = MFCreateTopoLoader(&object->topo_loader)))
3661 goto failed;
3663 if (!object->quality_manager && !without_quality_manager &&
3664 FAILED(hr = MFCreateStandardQualityManager(&object->quality_manager)))
3666 goto failed;
3669 if (object->quality_manager && FAILED(hr = IMFQualityManager_NotifyPresentationClock(object->quality_manager,
3670 object->clock)))
3672 goto failed;
3675 *session = &object->IMFMediaSession_iface;
3677 return S_OK;
3679 failed:
3680 IMFMediaSession_Release(&object->IMFMediaSession_iface);
3681 return hr;
3684 static HRESULT WINAPI standard_quality_manager_QueryInterface(IMFQualityManager *iface, REFIID riid, void **out)
3686 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3688 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
3690 if (IsEqualIID(riid, &IID_IMFQualityManager) ||
3691 IsEqualIID(riid, &IID_IUnknown))
3693 *out = iface;
3695 else if (IsEqualIID(riid, &IID_IMFClockStateSink))
3697 *out = &manager->IMFClockStateSink_iface;
3699 else
3701 WARN("Unsupported %s.\n", debugstr_guid(riid));
3702 *out = NULL;
3703 return E_NOINTERFACE;
3706 IUnknown_AddRef((IUnknown *)*out);
3707 return S_OK;
3710 static ULONG WINAPI standard_quality_manager_AddRef(IMFQualityManager *iface)
3712 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3713 ULONG refcount = InterlockedIncrement(&manager->refcount);
3715 TRACE("%p, refcount %u.\n", iface, refcount);
3717 return refcount;
3720 static ULONG WINAPI standard_quality_manager_Release(IMFQualityManager *iface)
3722 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3723 ULONG refcount = InterlockedDecrement(&manager->refcount);
3725 TRACE("%p, refcount %u.\n", iface, refcount);
3727 if (!refcount)
3729 if (manager->clock)
3730 IMFPresentationClock_Release(manager->clock);
3731 if (manager->topology)
3732 IMFTopology_Release(manager->topology);
3733 DeleteCriticalSection(&manager->cs);
3734 heap_free(manager);
3737 return refcount;
3740 static void standard_quality_manager_set_topology(struct quality_manager *manager, IMFTopology *topology)
3742 if (manager->topology)
3743 IMFTopology_Release(manager->topology);
3744 manager->topology = topology;
3745 if (manager->topology)
3746 IMFTopology_AddRef(manager->topology);
3749 static HRESULT WINAPI standard_quality_manager_NotifyTopology(IMFQualityManager *iface, IMFTopology *topology)
3751 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3752 HRESULT hr = S_OK;
3754 TRACE("%p, %p.\n", iface, topology);
3756 EnterCriticalSection(&manager->cs);
3757 if (manager->state == QUALITY_MANAGER_SHUT_DOWN)
3758 hr = MF_E_SHUTDOWN;
3759 else
3761 standard_quality_manager_set_topology(manager, topology);
3763 LeaveCriticalSection(&manager->cs);
3765 return hr;
3768 static void standard_quality_manager_release_clock(struct quality_manager *manager)
3770 if (manager->clock)
3772 IMFPresentationClock_RemoveClockStateSink(manager->clock, &manager->IMFClockStateSink_iface);
3773 IMFPresentationClock_Release(manager->clock);
3775 manager->clock = NULL;
3778 static HRESULT WINAPI standard_quality_manager_NotifyPresentationClock(IMFQualityManager *iface,
3779 IMFPresentationClock *clock)
3781 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3782 HRESULT hr = S_OK;
3784 TRACE("%p, %p.\n", iface, clock);
3786 EnterCriticalSection(&manager->cs);
3787 if (manager->state == QUALITY_MANAGER_SHUT_DOWN)
3788 hr = MF_E_SHUTDOWN;
3789 else if (!clock)
3790 hr = E_POINTER;
3791 else
3793 standard_quality_manager_release_clock(manager);
3794 manager->clock = clock;
3795 IMFPresentationClock_AddRef(manager->clock);
3796 if (FAILED(IMFPresentationClock_AddClockStateSink(manager->clock, &manager->IMFClockStateSink_iface)))
3797 WARN("Failed to set state sink.\n");
3799 LeaveCriticalSection(&manager->cs);
3801 return hr;
3804 static HRESULT WINAPI standard_quality_manager_NotifyProcessInput(IMFQualityManager *iface, IMFTopologyNode *node,
3805 LONG input_index, IMFSample *sample)
3807 TRACE("%p, %p, %d, %p stub.\n", iface, node, input_index, sample);
3809 return E_NOTIMPL;
3812 static HRESULT WINAPI standard_quality_manager_NotifyProcessOutput(IMFQualityManager *iface, IMFTopologyNode *node,
3813 LONG output_index, IMFSample *sample)
3815 TRACE("%p, %p, %d, %p stub.\n", iface, node, output_index, sample);
3817 return E_NOTIMPL;
3820 static HRESULT WINAPI standard_quality_manager_NotifyQualityEvent(IMFQualityManager *iface, IUnknown *object,
3821 IMFMediaEvent *event)
3823 FIXME("%p, %p, %p stub.\n", iface, object, event);
3825 return E_NOTIMPL;
3828 static HRESULT WINAPI standard_quality_manager_Shutdown(IMFQualityManager *iface)
3830 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3832 TRACE("%p.\n", iface);
3834 EnterCriticalSection(&manager->cs);
3835 if (manager->state != QUALITY_MANAGER_SHUT_DOWN)
3837 standard_quality_manager_release_clock(manager);
3838 standard_quality_manager_set_topology(manager, NULL);
3839 manager->state = QUALITY_MANAGER_SHUT_DOWN;
3841 LeaveCriticalSection(&manager->cs);
3843 return S_OK;
3846 static const IMFQualityManagerVtbl standard_quality_manager_vtbl =
3848 standard_quality_manager_QueryInterface,
3849 standard_quality_manager_AddRef,
3850 standard_quality_manager_Release,
3851 standard_quality_manager_NotifyTopology,
3852 standard_quality_manager_NotifyPresentationClock,
3853 standard_quality_manager_NotifyProcessInput,
3854 standard_quality_manager_NotifyProcessOutput,
3855 standard_quality_manager_NotifyQualityEvent,
3856 standard_quality_manager_Shutdown,
3859 static HRESULT WINAPI standard_quality_manager_sink_QueryInterface(IMFClockStateSink *iface,
3860 REFIID riid, void **obj)
3862 struct quality_manager *manager = impl_from_qm_IMFClockStateSink(iface);
3863 return IMFQualityManager_QueryInterface(&manager->IMFQualityManager_iface, riid, obj);
3866 static ULONG WINAPI standard_quality_manager_sink_AddRef(IMFClockStateSink *iface)
3868 struct quality_manager *manager = impl_from_qm_IMFClockStateSink(iface);
3869 return IMFQualityManager_AddRef(&manager->IMFQualityManager_iface);
3872 static ULONG WINAPI standard_quality_manager_sink_Release(IMFClockStateSink *iface)
3874 struct quality_manager *manager = impl_from_qm_IMFClockStateSink(iface);
3875 return IMFQualityManager_Release(&manager->IMFQualityManager_iface);
3878 static HRESULT WINAPI standard_quality_manager_sink_OnClockStart(IMFClockStateSink *iface,
3879 MFTIME systime, LONGLONG offset)
3881 return S_OK;
3884 static HRESULT WINAPI standard_quality_manager_sink_OnClockStop(IMFClockStateSink *iface,
3885 MFTIME systime)
3887 return S_OK;
3890 static HRESULT WINAPI standard_quality_manager_sink_OnClockPause(IMFClockStateSink *iface,
3891 MFTIME systime)
3893 return S_OK;
3896 static HRESULT WINAPI standard_quality_manager_sink_OnClockRestart(IMFClockStateSink *iface,
3897 MFTIME systime)
3899 return S_OK;
3902 static HRESULT WINAPI standard_quality_manager_sink_OnClockSetRate(IMFClockStateSink *iface,
3903 MFTIME systime, float rate)
3905 return S_OK;
3908 static const IMFClockStateSinkVtbl standard_quality_manager_sink_vtbl =
3910 standard_quality_manager_sink_QueryInterface,
3911 standard_quality_manager_sink_AddRef,
3912 standard_quality_manager_sink_Release,
3913 standard_quality_manager_sink_OnClockStart,
3914 standard_quality_manager_sink_OnClockStop,
3915 standard_quality_manager_sink_OnClockPause,
3916 standard_quality_manager_sink_OnClockRestart,
3917 standard_quality_manager_sink_OnClockSetRate,
3920 HRESULT WINAPI MFCreateStandardQualityManager(IMFQualityManager **manager)
3922 struct quality_manager *object;
3924 TRACE("%p.\n", manager);
3926 object = heap_alloc_zero(sizeof(*object));
3927 if (!object)
3928 return E_OUTOFMEMORY;
3930 object->IMFQualityManager_iface.lpVtbl = &standard_quality_manager_vtbl;
3931 object->IMFClockStateSink_iface.lpVtbl = &standard_quality_manager_sink_vtbl;
3932 object->refcount = 1;
3933 InitializeCriticalSection(&object->cs);
3935 *manager = &object->IMFQualityManager_iface;
3937 return S_OK;