mf/session: Fail start requests when no topology was set.
[wine.git] / dlls / mf / session.c
blob0377b19c51f46d86a488a805ec2e8d12402503ee
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/list.h"
33 #include "mf_private.h"
35 #include "initguid.h"
37 DEFINE_GUID(_MF_TOPONODE_IMFActivate, 0x33706f4a, 0x309a, 0x49be, 0xa8, 0xdd, 0xe7, 0xc0, 0x87, 0x5e, 0xb6, 0x79);
39 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
41 enum session_command
43 SESSION_CMD_CLEAR_TOPOLOGIES,
44 SESSION_CMD_CLOSE,
45 SESSION_CMD_SET_TOPOLOGY,
46 SESSION_CMD_START,
47 SESSION_CMD_PAUSE,
48 SESSION_CMD_STOP,
49 /* Internally used commands. */
50 SESSION_CMD_END,
51 SESSION_CMD_QM_NOTIFY_TOPOLOGY,
52 SESSION_CMD_SA_READY,
55 struct session_op
57 IUnknown IUnknown_iface;
58 LONG refcount;
59 enum session_command command;
60 union
62 struct
64 DWORD flags;
65 IMFTopology *topology;
66 } set_topology;
67 struct
69 GUID time_format;
70 PROPVARIANT start_position;
71 } start;
72 struct
74 IMFTopology *topology;
75 } notify_topology;
76 struct
78 TOPOID node_id;
79 } sa_ready;
80 } u;
81 struct list entry;
84 struct queued_topology
86 struct list entry;
87 IMFTopology *topology;
88 MF_TOPOSTATUS status;
91 enum session_state
93 SESSION_STATE_STOPPED = 0,
94 SESSION_STATE_STARTING_SOURCES,
95 SESSION_STATE_PREROLLING_SINKS,
96 SESSION_STATE_STARTING_SINKS,
97 SESSION_STATE_STARTED,
98 SESSION_STATE_PAUSING_SINKS,
99 SESSION_STATE_PAUSING_SOURCES,
100 SESSION_STATE_PAUSED,
101 SESSION_STATE_STOPPING_SINKS,
102 SESSION_STATE_STOPPING_SOURCES,
103 SESSION_STATE_FINALIZING_SINKS,
104 SESSION_STATE_CLOSED,
105 SESSION_STATE_SHUT_DOWN,
108 enum object_state
110 OBJ_STATE_STOPPED = 0,
111 OBJ_STATE_STARTED,
112 OBJ_STATE_PAUSED,
113 OBJ_STATE_PREROLLED,
114 OBJ_STATE_INVALID,
117 enum media_source_flags
119 SOURCE_FLAG_END_OF_PRESENTATION = 0x1,
122 struct media_source
124 struct list entry;
125 IMFMediaSource *source;
126 IMFPresentationDescriptor *pd;
127 enum object_state state;
128 unsigned int flags;
131 struct media_sink
133 struct list entry;
134 IMFMediaSink *sink;
135 IMFMediaSinkPreroll *preroll;
136 IMFMediaEventGenerator *event_generator;
137 BOOL finalized;
140 struct sample
142 struct list entry;
143 IMFSample *sample;
146 struct transform_stream
148 struct list samples;
149 unsigned int requests;
150 unsigned int min_buffer_size;
153 enum topo_node_flags
155 TOPO_NODE_END_OF_STREAM = 0x1,
158 struct topo_node
160 struct list entry;
161 struct media_session *session;
162 MF_TOPOLOGY_TYPE type;
163 TOPOID node_id;
164 IMFTopologyNode *node;
165 enum object_state state;
166 unsigned int flags;
167 union
169 IMFMediaStream *source_stream;
170 IMFStreamSink *sink_stream;
171 IMFTransform *transform;
172 IUnknown *object;
173 } object;
175 union
177 struct
179 IMFMediaSource *source;
180 unsigned int stream_id;
181 } source;
182 struct
184 unsigned int requests;
185 IMFVideoSampleAllocatorNotify notify_cb;
186 IMFVideoSampleAllocator *allocator;
187 IMFVideoSampleAllocatorCallback *allocator_cb;
188 } sink;
189 struct
191 struct transform_stream *inputs;
192 unsigned int *input_map;
193 unsigned int input_count;
195 struct transform_stream *outputs;
196 unsigned int *output_map;
197 unsigned int output_count;
198 } transform;
199 } u;
202 enum presentation_flags
204 SESSION_FLAG_SOURCES_SUBSCRIBED = 0x1,
205 SESSION_FLAG_PRESENTATION_CLOCK_SET = 0x2,
206 SESSION_FLAG_FINALIZE_SINKS = 0x4,
207 SESSION_FLAG_NEEDS_PREROLL = 0x8,
208 SESSION_FLAG_END_OF_PRESENTATION = 0x10,
211 struct media_session
213 IMFMediaSession IMFMediaSession_iface;
214 IMFGetService IMFGetService_iface;
215 IMFRateSupport IMFRateSupport_iface;
216 IMFRateControl IMFRateControl_iface;
217 IMFTopologyNodeAttributeEditor IMFTopologyNodeAttributeEditor_iface;
218 IMFAsyncCallback commands_callback;
219 IMFAsyncCallback events_callback;
220 IMFAsyncCallback sink_finalizer_callback;
221 LONG refcount;
222 IMFMediaEventQueue *event_queue;
223 IMFPresentationClock *clock;
224 IMFPresentationTimeSource *system_time_source;
225 IMFRateControl *clock_rate_control;
226 IMFTopoLoader *topo_loader;
227 IMFQualityManager *quality_manager;
228 struct
230 IMFTopology *current_topology;
231 MF_TOPOSTATUS topo_status;
232 MFTIME clock_stop_time;
233 unsigned int flags;
234 struct list sources;
235 struct list sinks;
236 struct list nodes;
238 /* Latest Start() arguments. */
239 GUID time_format;
240 PROPVARIANT start_position;
241 } presentation;
242 struct list topologies;
243 struct list commands;
244 enum session_state state;
245 DWORD caps;
246 CRITICAL_SECTION cs;
249 enum quality_manager_state
251 QUALITY_MANAGER_READY = 0,
252 QUALITY_MANAGER_SHUT_DOWN,
255 struct quality_manager
257 IMFQualityManager IMFQualityManager_iface;
258 IMFClockStateSink IMFClockStateSink_iface;
259 LONG refcount;
261 IMFTopology *topology;
262 IMFPresentationClock *clock;
263 unsigned int state;
264 CRITICAL_SECTION cs;
267 static inline struct media_session *impl_from_IMFMediaSession(IMFMediaSession *iface)
269 return CONTAINING_RECORD(iface, struct media_session, IMFMediaSession_iface);
272 static struct media_session *impl_from_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
274 return CONTAINING_RECORD(iface, struct media_session, commands_callback);
277 static struct media_session *impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
279 return CONTAINING_RECORD(iface, struct media_session, events_callback);
282 static struct media_session *impl_from_sink_finalizer_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
284 return CONTAINING_RECORD(iface, struct media_session, sink_finalizer_callback);
287 static struct media_session *impl_from_IMFGetService(IMFGetService *iface)
289 return CONTAINING_RECORD(iface, struct media_session, IMFGetService_iface);
292 static struct media_session *impl_session_from_IMFRateSupport(IMFRateSupport *iface)
294 return CONTAINING_RECORD(iface, struct media_session, IMFRateSupport_iface);
297 static struct media_session *impl_session_from_IMFRateControl(IMFRateControl *iface)
299 return CONTAINING_RECORD(iface, struct media_session, IMFRateControl_iface);
302 static struct media_session *impl_session_from_IMFTopologyNodeAttributeEditor(IMFTopologyNodeAttributeEditor *iface)
304 return CONTAINING_RECORD(iface, struct media_session, IMFTopologyNodeAttributeEditor_iface);
307 static struct session_op *impl_op_from_IUnknown(IUnknown *iface)
309 return CONTAINING_RECORD(iface, struct session_op, IUnknown_iface);
312 static struct quality_manager *impl_from_IMFQualityManager(IMFQualityManager *iface)
314 return CONTAINING_RECORD(iface, struct quality_manager, IMFQualityManager_iface);
317 static struct quality_manager *impl_from_qm_IMFClockStateSink(IMFClockStateSink *iface)
319 return CONTAINING_RECORD(iface, struct quality_manager, IMFClockStateSink_iface);
322 static struct topo_node *impl_node_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify *iface)
324 return CONTAINING_RECORD(iface, struct topo_node, u.sink.notify_cb);
327 /* IMFLocalMFTRegistration */
328 static HRESULT WINAPI local_mft_registration_QueryInterface(IMFLocalMFTRegistration *iface, REFIID riid, void **obj)
330 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
332 if (IsEqualIID(riid, &IID_IMFLocalMFTRegistration) ||
333 IsEqualIID(riid, &IID_IUnknown))
335 *obj = iface;
336 IMFLocalMFTRegistration_AddRef(iface);
337 return S_OK;
340 WARN("Unexpected %s.\n", debugstr_guid(riid));
341 *obj = NULL;
342 return E_NOINTERFACE;
345 static ULONG WINAPI local_mft_registration_AddRef(IMFLocalMFTRegistration *iface)
347 return 2;
350 static ULONG WINAPI local_mft_registration_Release(IMFLocalMFTRegistration *iface)
352 return 1;
355 static HRESULT WINAPI local_mft_registration_RegisterMFTs(IMFLocalMFTRegistration *iface, MFT_REGISTRATION_INFO *info,
356 DWORD count)
358 HRESULT hr = S_OK;
359 DWORD i;
361 TRACE("%p, %p, %u.\n", iface, info, count);
363 for (i = 0; i < count; ++i)
365 if (FAILED(hr = MFTRegisterLocalByCLSID(&info[i].clsid, &info[i].guidCategory, info[i].pszName,
366 info[i].uiFlags, info[i].cInTypes, info[i].pInTypes, info[i].cOutTypes, info[i].pOutTypes)))
368 break;
372 return hr;
375 static const IMFLocalMFTRegistrationVtbl local_mft_registration_vtbl =
377 local_mft_registration_QueryInterface,
378 local_mft_registration_AddRef,
379 local_mft_registration_Release,
380 local_mft_registration_RegisterMFTs,
383 static IMFLocalMFTRegistration local_mft_registration = { &local_mft_registration_vtbl };
385 static HRESULT WINAPI session_op_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
387 if (IsEqualIID(riid, &IID_IUnknown))
389 *obj = iface;
390 IUnknown_AddRef(iface);
391 return S_OK;
394 *obj = NULL;
395 return E_NOINTERFACE;
398 static ULONG WINAPI session_op_AddRef(IUnknown *iface)
400 struct session_op *op = impl_op_from_IUnknown(iface);
401 ULONG refcount = InterlockedIncrement(&op->refcount);
403 TRACE("%p, refcount %u.\n", iface, refcount);
405 return refcount;
408 static ULONG WINAPI session_op_Release(IUnknown *iface)
410 struct session_op *op = impl_op_from_IUnknown(iface);
411 ULONG refcount = InterlockedDecrement(&op->refcount);
413 TRACE("%p, refcount %u.\n", iface, refcount);
415 if (!refcount)
417 switch (op->command)
419 case SESSION_CMD_SET_TOPOLOGY:
420 if (op->u.set_topology.topology)
421 IMFTopology_Release(op->u.set_topology.topology);
422 break;
423 case SESSION_CMD_START:
424 PropVariantClear(&op->u.start.start_position);
425 break;
426 case SESSION_CMD_QM_NOTIFY_TOPOLOGY:
427 if (op->u.notify_topology.topology)
428 IMFTopology_Release(op->u.notify_topology.topology);
429 break;
430 default:
433 free(op);
436 return refcount;
439 static const IUnknownVtbl session_op_vtbl =
441 session_op_QueryInterface,
442 session_op_AddRef,
443 session_op_Release,
446 static HRESULT create_session_op(enum session_command command, struct session_op **ret)
448 struct session_op *op;
450 if (!(op = calloc(1, sizeof(*op))))
451 return E_OUTOFMEMORY;
453 op->IUnknown_iface.lpVtbl = &session_op_vtbl;
454 op->refcount = 1;
455 op->command = command;
457 *ret = op;
459 return S_OK;
462 static HRESULT session_is_shut_down(struct media_session *session)
464 return session->state == SESSION_STATE_SHUT_DOWN ? MF_E_SHUTDOWN : S_OK;
467 static void session_push_back_command(struct media_session *session, enum session_command command)
469 struct session_op *op;
471 if (SUCCEEDED(create_session_op(command, &op)))
472 list_add_head(&session->commands, &op->entry);
475 static HRESULT session_submit_command(struct media_session *session, struct session_op *op)
477 HRESULT hr;
479 EnterCriticalSection(&session->cs);
480 if (SUCCEEDED(hr = session_is_shut_down(session)))
482 if (list_empty(&session->commands))
483 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface);
484 list_add_tail(&session->commands, &op->entry);
485 IUnknown_AddRef(&op->IUnknown_iface);
487 LeaveCriticalSection(&session->cs);
489 return hr;
492 static HRESULT session_submit_simple_command(struct media_session *session, enum session_command command)
494 struct session_op *op;
495 HRESULT hr;
497 if (FAILED(hr = create_session_op(command, &op)))
498 return hr;
500 hr = session_submit_command(session, op);
501 IUnknown_Release(&op->IUnknown_iface);
502 return hr;
505 static void session_clear_queued_topologies(struct media_session *session)
507 struct queued_topology *ptr, *next;
509 LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &session->topologies, struct queued_topology, entry)
511 list_remove(&ptr->entry);
512 IMFTopology_Release(ptr->topology);
513 free(ptr);
517 static void session_set_topo_status(struct media_session *session, HRESULT status,
518 MF_TOPOSTATUS topo_status)
520 IMFMediaEvent *event;
521 PROPVARIANT param;
523 if (topo_status == MF_TOPOSTATUS_INVALID)
524 return;
526 if (list_empty(&session->topologies))
528 FIXME("Unexpectedly empty topology queue.\n");
529 return;
532 if (topo_status > session->presentation.topo_status)
534 struct queued_topology *topology = LIST_ENTRY(list_head(&session->topologies), struct queued_topology, entry);
536 param.vt = VT_UNKNOWN;
537 param.punkVal = (IUnknown *)topology->topology;
539 if (FAILED(MFCreateMediaEvent(MESessionTopologyStatus, &GUID_NULL, status, &param, &event)))
540 return;
542 session->presentation.topo_status = topo_status;
544 IMFMediaEvent_SetUINT32(event, &MF_EVENT_TOPOLOGY_STATUS, topo_status);
545 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
546 IMFMediaEvent_Release(event);
550 static HRESULT session_bind_output_nodes(IMFTopology *topology)
552 MF_TOPOLOGY_TYPE node_type;
553 IMFStreamSink *stream_sink;
554 IMFMediaSink *media_sink;
555 WORD node_count = 0, i;
556 IMFTopologyNode *node;
557 IMFActivate *activate;
558 UINT32 stream_id;
559 IUnknown *object;
560 HRESULT hr;
562 hr = IMFTopology_GetNodeCount(topology, &node_count);
564 for (i = 0; i < node_count; ++i)
566 if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
567 break;
569 if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type)) || node_type != MF_TOPOLOGY_OUTPUT_NODE)
571 IMFTopologyNode_Release(node);
572 continue;
575 if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object)))
577 stream_sink = NULL;
578 if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&stream_sink)))
580 if (SUCCEEDED(hr = IUnknown_QueryInterface(object, &IID_IMFActivate, (void **)&activate)))
582 if (SUCCEEDED(hr = IMFActivate_ActivateObject(activate, &IID_IMFMediaSink, (void **)&media_sink)))
584 if (FAILED(IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_STREAMID, &stream_id)))
585 stream_id = 0;
587 stream_sink = NULL;
588 if (FAILED(IMFMediaSink_GetStreamSinkById(media_sink, stream_id, &stream_sink)))
589 hr = IMFMediaSink_AddStreamSink(media_sink, stream_id, NULL, &stream_sink);
591 if (stream_sink)
592 hr = IMFTopologyNode_SetObject(node, (IUnknown *)stream_sink);
594 IMFMediaSink_Release(media_sink);
597 if (SUCCEEDED(hr))
598 IMFTopologyNode_SetUnknown(node, &_MF_TOPONODE_IMFActivate, (IUnknown *)activate);
600 IMFActivate_Release(activate);
604 if (stream_sink)
605 IMFStreamSink_Release(stream_sink);
606 IUnknown_Release(object);
609 IMFTopologyNode_Release(node);
612 return hr;
615 static void session_set_caps(struct media_session *session, DWORD caps)
617 DWORD delta = session->caps ^ caps;
618 IMFMediaEvent *event;
620 /* Delta is documented to reflect rate value changes as well, but it's not clear what to compare
621 them to, since session always queries for current object rates. */
622 if (!delta)
623 return;
625 session->caps = caps;
627 if (FAILED(MFCreateMediaEvent(MESessionCapabilitiesChanged, &GUID_NULL, S_OK, NULL, &event)))
628 return;
630 IMFMediaEvent_SetUINT32(event, &MF_EVENT_SESSIONCAPS, caps);
631 IMFMediaEvent_SetUINT32(event, &MF_EVENT_SESSIONCAPS_DELTA, delta);
633 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
634 IMFMediaEvent_Release(event);
637 static void transform_release_sample(struct sample *sample)
639 list_remove(&sample->entry);
640 if (sample->sample)
641 IMFSample_Release(sample->sample);
642 free(sample);
645 static void transform_stream_drop_samples(struct transform_stream *stream)
647 struct sample *sample, *sample2;
649 LIST_FOR_EACH_ENTRY_SAFE(sample, sample2, &stream->samples, struct sample, entry)
650 transform_release_sample(sample);
653 static void release_topo_node(struct topo_node *node)
655 unsigned int i;
657 switch (node->type)
659 case MF_TOPOLOGY_SOURCESTREAM_NODE:
660 if (node->u.source.source)
661 IMFMediaSource_Release(node->u.source.source);
662 break;
663 case MF_TOPOLOGY_TRANSFORM_NODE:
664 for (i = 0; i < node->u.transform.input_count; ++i)
665 transform_stream_drop_samples(&node->u.transform.inputs[i]);
666 for (i = 0; i < node->u.transform.output_count; ++i)
667 transform_stream_drop_samples(&node->u.transform.outputs[i]);
668 free(node->u.transform.inputs);
669 free(node->u.transform.outputs);
670 free(node->u.transform.input_map);
671 free(node->u.transform.output_map);
672 break;
673 case MF_TOPOLOGY_OUTPUT_NODE:
674 if (node->u.sink.allocator)
675 IMFVideoSampleAllocator_Release(node->u.sink.allocator);
676 if (node->u.sink.allocator_cb)
678 IMFVideoSampleAllocatorCallback_SetCallback(node->u.sink.allocator_cb, NULL);
679 IMFVideoSampleAllocatorCallback_Release(node->u.sink.allocator_cb);
681 break;
682 default:
686 if (node->object.object)
687 IUnknown_Release(node->object.object);
688 if (node->node)
689 IMFTopologyNode_Release(node->node);
690 free(node);
693 static void session_shutdown_current_topology(struct media_session *session)
695 unsigned int shutdown, force_shutdown;
696 MF_TOPOLOGY_TYPE node_type;
697 IMFStreamSink *stream_sink;
698 IMFTopology *topology;
699 IMFTopologyNode *node;
700 IMFActivate *activate;
701 IMFMediaSink *sink;
702 WORD idx = 0;
703 HRESULT hr;
705 topology = session->presentation.current_topology;
706 force_shutdown = session->state == SESSION_STATE_SHUT_DOWN;
708 /* FIXME: should handle async MFTs, but these are not supported by the rest of the pipeline currently. */
710 while (SUCCEEDED(IMFTopology_GetNode(topology, idx++, &node)))
712 if (SUCCEEDED(IMFTopologyNode_GetNodeType(node, &node_type)) &&
713 node_type == MF_TOPOLOGY_OUTPUT_NODE)
715 shutdown = 1;
716 IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, &shutdown);
718 if (force_shutdown || shutdown)
720 if (SUCCEEDED(IMFTopologyNode_GetUnknown(node, &_MF_TOPONODE_IMFActivate, &IID_IMFActivate,
721 (void **)&activate)))
723 if (FAILED(hr = IMFActivate_ShutdownObject(activate)))
724 WARN("Failed to shut down activation object for the sink, hr %#x.\n", hr);
725 IMFActivate_Release(activate);
727 else if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink)))
729 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink)))
731 IMFMediaSink_Shutdown(sink);
732 IMFMediaSink_Release(sink);
735 IMFStreamSink_Release(stream_sink);
740 IMFTopologyNode_Release(node);
744 static void session_clear_command_list(struct media_session *session)
746 struct session_op *op, *op2;
748 LIST_FOR_EACH_ENTRY_SAFE(op, op2, &session->commands, struct session_op, entry)
750 list_remove(&op->entry);
751 IUnknown_Release(&op->IUnknown_iface);
755 static void session_clear_presentation(struct media_session *session)
757 struct media_source *source, *source2;
758 struct media_sink *sink, *sink2;
759 struct topo_node *node, *node2;
761 session_shutdown_current_topology(session);
763 IMFTopology_Clear(session->presentation.current_topology);
764 session->presentation.topo_status = MF_TOPOSTATUS_INVALID;
766 LIST_FOR_EACH_ENTRY_SAFE(source, source2, &session->presentation.sources, struct media_source, entry)
768 list_remove(&source->entry);
769 if (source->source)
770 IMFMediaSource_Release(source->source);
771 if (source->pd)
772 IMFPresentationDescriptor_Release(source->pd);
773 free(source);
776 LIST_FOR_EACH_ENTRY_SAFE(node, node2, &session->presentation.nodes, struct topo_node, entry)
778 list_remove(&node->entry);
779 release_topo_node(node);
782 LIST_FOR_EACH_ENTRY_SAFE(sink, sink2, &session->presentation.sinks, struct media_sink, entry)
784 list_remove(&sink->entry);
786 if (sink->sink)
787 IMFMediaSink_Release(sink->sink);
788 if (sink->preroll)
789 IMFMediaSinkPreroll_Release(sink->preroll);
790 if (sink->event_generator)
791 IMFMediaEventGenerator_Release(sink->event_generator);
792 free(sink);
796 static struct topo_node *session_get_node_by_id(const struct media_session *session, TOPOID id)
798 struct topo_node *node;
800 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
802 if (node->node_id == id)
803 return node;
806 return NULL;
809 static void session_command_complete(struct media_session *session)
811 struct session_op *op;
812 struct list *e;
814 /* Pop current command, submit next. */
815 if ((e = list_head(&session->commands)))
817 op = LIST_ENTRY(e, struct session_op, entry);
818 list_remove(&op->entry);
819 IUnknown_Release(&op->IUnknown_iface);
822 if ((e = list_head(&session->commands)))
824 op = LIST_ENTRY(e, struct session_op, entry);
825 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface);
829 static void session_command_complete_with_event(struct media_session *session, MediaEventType event,
830 HRESULT status, const PROPVARIANT *param)
832 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, event, &GUID_NULL, status, param);
833 session_command_complete(session);
836 static void session_start(struct media_session *session, const GUID *time_format, const PROPVARIANT *start_position)
838 struct media_source *source;
839 HRESULT hr;
841 switch (session->state)
843 case SESSION_STATE_STOPPED:
845 /* Start request with no current topology. */
846 if (session->presentation.topo_status == MF_TOPOSTATUS_INVALID)
848 session_command_complete_with_event(session, MESessionStarted, MF_E_INVALIDREQUEST, NULL);
849 break;
852 /* fallthrough */
853 case SESSION_STATE_PAUSED:
855 session->presentation.time_format = *time_format;
856 session->presentation.start_position.vt = VT_EMPTY;
857 PropVariantCopy(&session->presentation.start_position, start_position);
859 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
861 if (!(session->presentation.flags & SESSION_FLAG_SOURCES_SUBSCRIBED))
863 if (FAILED(hr = IMFMediaSource_BeginGetEvent(source->source, &session->events_callback,
864 (IUnknown *)source->source)))
866 WARN("Failed to subscribe to source events, hr %#x.\n", hr);
870 if (FAILED(hr = IMFMediaSource_Start(source->source, source->pd, &GUID_NULL, start_position)))
871 WARN("Failed to start media source %p, hr %#x.\n", source->source, hr);
874 session->presentation.flags |= SESSION_FLAG_SOURCES_SUBSCRIBED;
875 session->state = SESSION_STATE_STARTING_SOURCES;
876 break;
877 case SESSION_STATE_STARTED:
878 FIXME("Seeking is not implemented.\n");
879 session_command_complete(session);
880 break;
881 default:
882 session_command_complete_with_event(session, MESessionStarted, MF_E_INVALIDREQUEST, NULL);
883 break;
887 static void session_set_started(struct media_session *session)
889 struct media_source *source;
890 unsigned int caps, flags;
891 IMFMediaEvent *event;
893 session->state = SESSION_STATE_STARTED;
895 caps = session->caps | MFSESSIONCAP_PAUSE;
897 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
899 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source->source, &flags)))
901 if (!(flags & MFMEDIASOURCE_CAN_PAUSE))
903 caps &= ~MFSESSIONCAP_PAUSE;
904 break;
909 session_set_caps(session, caps);
911 if (SUCCEEDED(MFCreateMediaEvent(MESessionStarted, &GUID_NULL, S_OK, NULL, &event)))
913 IMFMediaEvent_SetUINT64(event, &MF_EVENT_PRESENTATION_TIME_OFFSET, 0);
914 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
915 IMFMediaEvent_Release(event);
917 session_command_complete(session);
920 static void session_set_paused(struct media_session *session, unsigned int state, HRESULT status)
922 /* Failed event status could indicate a failure during normal transition to paused state,
923 or an attempt to pause from invalid initial state. To finalize failed transition in the former case,
924 state is still forced to PAUSED, otherwise previous state is retained. */
925 if (state != ~0u) session->state = state;
926 if (SUCCEEDED(status))
927 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
928 session_command_complete_with_event(session, MESessionPaused, status, NULL);
931 static void session_set_closed(struct media_session *session, HRESULT status)
933 session->state = SESSION_STATE_CLOSED;
934 if (SUCCEEDED(status))
935 session_set_caps(session, session->caps & ~(MFSESSIONCAP_START | MFSESSIONCAP_SEEK));
936 session_command_complete_with_event(session, MESessionClosed, status, NULL);
939 static void session_pause(struct media_session *session)
941 unsigned int state = ~0u;
942 HRESULT hr;
944 switch (session->state)
946 case SESSION_STATE_STARTED:
948 /* Transition in two steps - pause the clock, wait for sinks, then pause sources. */
949 if (SUCCEEDED(hr = IMFPresentationClock_Pause(session->clock)))
950 session->state = SESSION_STATE_PAUSING_SINKS;
951 state = SESSION_STATE_PAUSED;
953 break;
955 case SESSION_STATE_STOPPED:
956 hr = MF_E_SESSION_PAUSEWHILESTOPPED;
957 break;
958 default:
959 hr = MF_E_INVALIDREQUEST;
962 if (FAILED(hr))
963 session_set_paused(session, state, hr);
966 static void session_clear_end_of_presentation(struct media_session *session)
968 struct media_source *source;
969 struct topo_node *node;
971 session->presentation.flags &= ~SESSION_FLAG_END_OF_PRESENTATION;
972 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
974 source->flags &= ~SOURCE_FLAG_END_OF_PRESENTATION;
976 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
978 node->flags &= ~TOPO_NODE_END_OF_STREAM;
980 session->presentation.topo_status = MF_TOPOSTATUS_READY;
983 static void session_set_stopped(struct media_session *session, HRESULT status)
985 MediaEventType event_type;
986 IMFMediaEvent *event;
988 session->state = SESSION_STATE_STOPPED;
989 event_type = session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION ? MESessionEnded : MESessionStopped;
991 if (SUCCEEDED(MFCreateMediaEvent(event_type, &GUID_NULL, status, NULL, &event)))
993 IMFMediaEvent_SetUINT64(event, &MF_SESSION_APPROX_EVENT_OCCURRENCE_TIME, session->presentation.clock_stop_time);
994 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
995 IMFMediaEvent_Release(event);
997 session_clear_end_of_presentation(session);
998 session_command_complete(session);
1001 static void session_stop(struct media_session *session)
1003 HRESULT hr = MF_E_INVALIDREQUEST;
1005 switch (session->state)
1007 case SESSION_STATE_STARTED:
1008 case SESSION_STATE_PAUSED:
1010 /* Transition in two steps - stop the clock, wait for sinks, then stop sources. */
1011 IMFPresentationClock_GetTime(session->clock, &session->presentation.clock_stop_time);
1012 if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock)))
1013 session->state = SESSION_STATE_STOPPING_SINKS;
1014 else
1015 session_set_stopped(session, hr);
1017 break;
1018 case SESSION_STATE_STOPPED:
1019 hr = S_OK;
1020 /* fallthrough */
1021 default:
1022 session_command_complete_with_event(session, MESessionStopped, hr, NULL);
1023 break;
1027 static HRESULT session_finalize_sinks(struct media_session *session)
1029 IMFFinalizableMediaSink *fin_sink;
1030 BOOL sinks_finalized = TRUE;
1031 struct media_sink *sink;
1032 HRESULT hr = S_OK;
1034 session->presentation.flags &= ~SESSION_FLAG_FINALIZE_SINKS;
1035 session->state = SESSION_STATE_FINALIZING_SINKS;
1037 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
1039 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink->sink, &IID_IMFFinalizableMediaSink, (void **)&fin_sink)))
1041 hr = IMFFinalizableMediaSink_BeginFinalize(fin_sink, &session->sink_finalizer_callback,
1042 (IUnknown *)fin_sink);
1043 IMFFinalizableMediaSink_Release(fin_sink);
1044 if (FAILED(hr))
1045 break;
1046 sinks_finalized = FALSE;
1048 else
1049 sink->finalized = TRUE;
1052 if (sinks_finalized)
1053 session_set_closed(session, hr);
1055 return hr;
1058 static void session_close(struct media_session *session)
1060 HRESULT hr = S_OK;
1062 switch (session->state)
1064 case SESSION_STATE_STOPPED:
1065 hr = session_finalize_sinks(session);
1066 break;
1067 case SESSION_STATE_STARTED:
1068 case SESSION_STATE_PAUSED:
1069 session->presentation.flags |= SESSION_FLAG_FINALIZE_SINKS;
1070 if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock)))
1071 session->state = SESSION_STATE_STOPPING_SINKS;
1072 break;
1073 default:
1074 hr = MF_E_INVALIDREQUEST;
1075 break;
1078 session_clear_queued_topologies(session);
1079 if (FAILED(hr))
1080 session_set_closed(session, hr);
1083 static void session_clear_topologies(struct media_session *session)
1085 HRESULT hr = S_OK;
1087 if (session->state == SESSION_STATE_CLOSED)
1088 hr = MF_E_INVALIDREQUEST;
1089 else
1090 session_clear_queued_topologies(session);
1091 session_command_complete_with_event(session, MESessionTopologiesCleared, hr, NULL);
1094 static struct media_source *session_get_media_source(struct media_session *session, IMFMediaSource *source)
1096 struct media_source *cur;
1098 LIST_FOR_EACH_ENTRY(cur, &session->presentation.sources, struct media_source, entry)
1100 if (source == cur->source)
1101 return cur;
1104 return NULL;
1107 static void session_release_media_source(struct media_source *source)
1109 IMFMediaSource_Release(source->source);
1110 if (source->pd)
1111 IMFPresentationDescriptor_Release(source->pd);
1112 free(source);
1115 static HRESULT session_add_media_source(struct media_session *session, IMFTopologyNode *node, IMFMediaSource *source)
1117 struct media_source *media_source;
1118 HRESULT hr;
1120 if (session_get_media_source(session, source))
1121 return S_FALSE;
1123 if (!(media_source = calloc(1, sizeof(*media_source))))
1124 return E_OUTOFMEMORY;
1126 media_source->source = source;
1127 IMFMediaSource_AddRef(media_source->source);
1129 hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, &IID_IMFPresentationDescriptor,
1130 (void **)&media_source->pd);
1132 if (SUCCEEDED(hr))
1133 list_add_tail(&session->presentation.sources, &media_source->entry);
1134 else
1135 session_release_media_source(media_source);
1137 return hr;
1140 static void session_raise_topology_set(struct media_session *session, IMFTopology *topology, HRESULT status)
1142 PROPVARIANT param;
1144 param.vt = topology ? VT_UNKNOWN : VT_EMPTY;
1145 param.punkVal = (IUnknown *)topology;
1147 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologySet, &GUID_NULL, status, &param);
1150 static DWORD session_get_object_rate_caps(IUnknown *object)
1152 IMFRateSupport *rate_support;
1153 DWORD caps = 0;
1154 float rate;
1156 if (SUCCEEDED(MFGetService(object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support)))
1158 rate = 0.0f;
1159 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support, MFRATE_FORWARD, TRUE, &rate)) && rate != 0.0f)
1160 caps |= MFSESSIONCAP_RATE_FORWARD;
1162 rate = 0.0f;
1163 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support, MFRATE_REVERSE, TRUE, &rate)) && rate != 0.0f)
1164 caps |= MFSESSIONCAP_RATE_REVERSE;
1166 IMFRateSupport_Release(rate_support);
1169 return caps;
1172 static HRESULT session_add_media_sink(struct media_session *session, IMFTopologyNode *node, IMFMediaSink *sink)
1174 struct media_sink *media_sink;
1175 unsigned int disable_preroll = 0;
1176 DWORD flags;
1178 LIST_FOR_EACH_ENTRY(media_sink, &session->presentation.sinks, struct media_sink, entry)
1180 if (sink == media_sink->sink)
1181 return S_FALSE;
1184 if (!(media_sink = calloc(1, sizeof(*media_sink))))
1185 return E_OUTOFMEMORY;
1187 media_sink->sink = sink;
1188 IMFMediaSink_AddRef(media_sink->sink);
1190 IMFMediaSink_QueryInterface(media_sink->sink, &IID_IMFMediaEventGenerator, (void **)&media_sink->event_generator);
1192 IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_DISABLE_PREROLL, &disable_preroll);
1193 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink, &flags)) && flags & MEDIASINK_CAN_PREROLL && !disable_preroll)
1195 if (SUCCEEDED(IMFMediaSink_QueryInterface(media_sink->sink, &IID_IMFMediaSinkPreroll, (void **)&media_sink->preroll)))
1196 session->presentation.flags |= SESSION_FLAG_NEEDS_PREROLL;
1199 list_add_tail(&session->presentation.sinks, &media_sink->entry);
1201 return S_OK;
1204 static unsigned int transform_node_get_stream_id(struct topo_node *node, BOOL output, unsigned int index)
1206 unsigned int *map = output ? node->u.transform.output_map : node->u.transform.input_map;
1207 return map ? map[index] : index;
1210 static HRESULT session_set_transform_stream_info(struct topo_node *node)
1212 unsigned int *input_map = NULL, *output_map = NULL;
1213 unsigned int i, input_count, output_count, block_alignment;
1214 struct transform_stream *streams;
1215 IMFMediaType *media_type;
1216 GUID major = { 0 };
1217 HRESULT hr;
1219 hr = IMFTransform_GetStreamCount(node->object.transform, &input_count, &output_count);
1220 if (SUCCEEDED(hr) && (input_count > 1 || output_count > 1))
1222 input_map = calloc(input_count, sizeof(*input_map));
1223 output_map = calloc(output_count, sizeof(*output_map));
1224 if (FAILED(IMFTransform_GetStreamIDs(node->object.transform, input_count, input_map,
1225 output_count, output_map)))
1227 /* Assume sequential identifiers. */
1228 free(input_map);
1229 free(output_map);
1230 input_map = output_map = NULL;
1234 if (SUCCEEDED(hr))
1236 node->u.transform.input_map = input_map;
1237 node->u.transform.output_map = output_map;
1239 streams = calloc(input_count, sizeof(*streams));
1240 for (i = 0; i < input_count; ++i)
1241 list_init(&streams[i].samples);
1242 node->u.transform.inputs = streams;
1243 node->u.transform.input_count = input_count;
1245 streams = calloc(output_count, sizeof(*streams));
1246 for (i = 0; i < output_count; ++i)
1248 list_init(&streams[i].samples);
1250 if (SUCCEEDED(IMFTransform_GetOutputCurrentType(node->object.transform,
1251 transform_node_get_stream_id(node, TRUE, i), &media_type)))
1253 if (SUCCEEDED(IMFMediaType_GetMajorType(media_type, &major)) && IsEqualGUID(&major, &MFMediaType_Audio)
1254 && SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment)))
1256 streams[i].min_buffer_size = block_alignment;
1258 IMFMediaType_Release(media_type);
1261 node->u.transform.outputs = streams;
1262 node->u.transform.output_count = output_count;
1265 return hr;
1268 static HRESULT session_get_stream_sink_type(IMFStreamSink *sink, IMFMediaType **media_type)
1270 IMFMediaTypeHandler *handler;
1271 HRESULT hr;
1273 if (SUCCEEDED(hr = IMFStreamSink_GetMediaTypeHandler(sink, &handler)))
1275 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, media_type);
1276 IMFMediaTypeHandler_Release(handler);
1279 return hr;
1282 static HRESULT WINAPI node_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify *iface,
1283 REFIID riid, void **obj)
1285 if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorNotify) ||
1286 IsEqualIID(riid, &IID_IUnknown))
1288 *obj = iface;
1289 IMFVideoSampleAllocatorNotify_AddRef(iface);
1290 return S_OK;
1293 *obj = NULL;
1294 return E_NOINTERFACE;
1297 static ULONG WINAPI node_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify *iface)
1299 return 2;
1302 static ULONG WINAPI node_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify *iface)
1304 return 1;
1307 static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output);
1309 static HRESULT WINAPI node_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify *iface)
1311 struct topo_node *topo_node = impl_node_from_IMFVideoSampleAllocatorNotify(iface);
1312 struct session_op *op;
1314 if (SUCCEEDED(create_session_op(SESSION_CMD_SA_READY, &op)))
1316 op->u.sa_ready.node_id = topo_node->node_id;
1317 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &topo_node->session->commands_callback, &op->IUnknown_iface);
1318 IUnknown_Release(&op->IUnknown_iface);
1321 return S_OK;
1324 static const IMFVideoSampleAllocatorNotifyVtbl node_sample_allocator_cb_vtbl =
1326 node_sample_allocator_cb_QueryInterface,
1327 node_sample_allocator_cb_AddRef,
1328 node_sample_allocator_cb_Release,
1329 node_sample_allocator_cb_NotifyRelease,
1332 static HRESULT session_append_node(struct media_session *session, IMFTopologyNode *node)
1334 struct topo_node *topo_node;
1335 IMFMediaSink *media_sink;
1336 IMFMediaType *media_type;
1337 IMFStreamDescriptor *sd;
1338 HRESULT hr = S_OK;
1340 if (!(topo_node = calloc(1, sizeof(*topo_node))))
1341 return E_OUTOFMEMORY;
1343 IMFTopologyNode_GetNodeType(node, &topo_node->type);
1344 IMFTopologyNode_GetTopoNodeID(node, &topo_node->node_id);
1345 topo_node->node = node;
1346 IMFTopologyNode_AddRef(topo_node->node);
1347 topo_node->session = session;
1349 switch (topo_node->type)
1351 case MF_TOPOLOGY_OUTPUT_NODE:
1352 topo_node->u.sink.notify_cb.lpVtbl = &node_sample_allocator_cb_vtbl;
1354 if (FAILED(hr = topology_node_get_object(node, &IID_IMFStreamSink, (void **)&topo_node->object.object)))
1356 WARN("Failed to get stream sink interface, hr %#x.\n", hr);
1357 break;
1360 if (FAILED(hr = IMFStreamSink_GetMediaSink(topo_node->object.sink_stream, &media_sink)))
1361 break;
1363 if (SUCCEEDED(hr = session_add_media_sink(session, node, media_sink)))
1365 if (SUCCEEDED(session_get_stream_sink_type(topo_node->object.sink_stream, &media_type)))
1367 if (SUCCEEDED(MFGetService(topo_node->object.object, &MR_VIDEO_ACCELERATION_SERVICE,
1368 &IID_IMFVideoSampleAllocator, (void **)&topo_node->u.sink.allocator)))
1370 if (FAILED(hr = IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node->u.sink.allocator,
1371 2, media_type)))
1373 WARN("Failed to initialize sample allocator for the stream, hr %#x.\n", hr);
1375 IMFVideoSampleAllocator_QueryInterface(topo_node->u.sink.allocator,
1376 &IID_IMFVideoSampleAllocatorCallback, (void **)&topo_node->u.sink.allocator_cb);
1377 IMFVideoSampleAllocatorCallback_SetCallback(topo_node->u.sink.allocator_cb,
1378 &topo_node->u.sink.notify_cb);
1380 IMFMediaType_Release(media_type);
1383 IMFMediaSink_Release(media_sink);
1385 break;
1386 case MF_TOPOLOGY_SOURCESTREAM_NODE:
1387 if (FAILED(IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_SOURCE, &IID_IMFMediaSource,
1388 (void **)&topo_node->u.source.source)))
1390 WARN("Missing MF_TOPONODE_SOURCE, hr %#x.\n", hr);
1391 break;
1394 if (FAILED(hr = session_add_media_source(session, node, topo_node->u.source.source)))
1395 break;
1397 if (FAILED(hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR,
1398 &IID_IMFStreamDescriptor, (void **)&sd)))
1400 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#x.\n", hr);
1401 break;
1404 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &topo_node->u.source.stream_id);
1405 IMFStreamDescriptor_Release(sd);
1407 break;
1408 case MF_TOPOLOGY_TRANSFORM_NODE:
1410 if (SUCCEEDED(hr = topology_node_get_object(node, &IID_IMFTransform, (void **)&topo_node->object.transform)))
1412 hr = session_set_transform_stream_info(topo_node);
1414 else
1415 WARN("Failed to get IMFTransform for MFT node, hr %#x.\n", hr);
1417 break;
1418 case MF_TOPOLOGY_TEE_NODE:
1419 FIXME("Unsupported node type %d.\n", topo_node->type);
1421 break;
1422 default:
1426 if (SUCCEEDED(hr))
1427 list_add_tail(&session->presentation.nodes, &topo_node->entry);
1428 else
1429 release_topo_node(topo_node);
1431 return hr;
1434 static HRESULT session_collect_nodes(struct media_session *session)
1436 IMFTopology *topology = session->presentation.current_topology;
1437 IMFTopologyNode *node;
1438 WORD i, count = 0;
1439 HRESULT hr;
1441 if (!list_empty(&session->presentation.nodes))
1442 return S_OK;
1444 if (FAILED(hr = IMFTopology_GetNodeCount(topology, &count)))
1445 return hr;
1447 for (i = 0; i < count; ++i)
1449 if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
1451 WARN("Failed to get node %u.\n", i);
1452 break;
1455 hr = session_append_node(session, node);
1456 IMFTopologyNode_Release(node);
1457 if (FAILED(hr))
1459 WARN("Failed to add node %u.\n", i);
1460 break;
1464 return hr;
1467 static HRESULT session_set_current_topology(struct media_session *session, IMFTopology *topology)
1469 struct media_source *source;
1470 DWORD caps, object_flags;
1471 struct media_sink *sink;
1472 struct topo_node *node;
1473 struct session_op *op;
1474 IMFMediaEvent *event;
1475 HRESULT hr;
1477 if (session->quality_manager)
1479 if (SUCCEEDED(create_session_op(SESSION_CMD_QM_NOTIFY_TOPOLOGY, &op)))
1481 op->u.notify_topology.topology = topology;
1482 IMFTopology_AddRef(op->u.notify_topology.topology);
1483 session_submit_command(session, op);
1484 IUnknown_Release(&op->IUnknown_iface);
1488 if (FAILED(hr = IMFTopology_CloneFrom(session->presentation.current_topology, topology)))
1490 WARN("Failed to clone topology, hr %#x.\n", hr);
1491 return hr;
1494 session_collect_nodes(session);
1496 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
1498 if (node->type == MF_TOPOLOGY_TRANSFORM_NODE)
1500 if (FAILED(hr = IMFTransform_ProcessMessage(node->object.transform,
1501 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0)))
1502 return hr;
1506 /* FIXME: attributes are all zero for now */
1507 if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime, &GUID_NULL, S_OK, NULL, &event)))
1509 IMFMediaEvent_SetUINT64(event, &MF_EVENT_START_PRESENTATION_TIME, 0);
1510 IMFMediaEvent_SetUINT64(event, &MF_EVENT_PRESENTATION_TIME_OFFSET, 0);
1511 IMFMediaEvent_SetUINT64(event, &MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT, 0);
1513 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
1514 IMFMediaEvent_Release(event);
1517 /* Update session caps. */
1518 caps = MFSESSIONCAP_START | MFSESSIONCAP_SEEK | MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE |
1519 MFSESSIONCAP_DOES_NOT_USE_NETWORK;
1521 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
1523 if (!caps)
1524 break;
1526 object_flags = 0;
1527 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source->source, &object_flags)))
1529 if (!(object_flags & MFMEDIASOURCE_DOES_NOT_USE_NETWORK))
1530 caps &= ~MFSESSIONCAP_DOES_NOT_USE_NETWORK;
1531 if (!(object_flags & MFMEDIASOURCE_CAN_SEEK))
1532 caps &= ~MFSESSIONCAP_SEEK;
1535 /* Mask unsupported rate caps. */
1537 caps &= session_get_object_rate_caps((IUnknown *)source->source)
1538 | ~(MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE);
1541 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
1543 if (!caps)
1544 break;
1546 object_flags = 0;
1547 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink->sink, &object_flags)))
1549 if (!(object_flags & MEDIASINK_RATELESS))
1550 caps &= session_get_object_rate_caps((IUnknown *)sink->sink)
1551 | ~(MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE);
1555 session_set_caps(session, caps);
1557 return S_OK;
1560 static void session_set_topology(struct media_session *session, DWORD flags, IMFTopology *topology)
1562 IMFTopology *resolved_topology = NULL;
1563 HRESULT hr = S_OK;
1565 /* Resolve unless claimed to be full. */
1566 if (!(flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT) && topology)
1568 if (!(flags & MFSESSION_SETTOPOLOGY_NORESOLUTION))
1570 hr = session_bind_output_nodes(topology);
1572 if (SUCCEEDED(hr))
1573 hr = IMFTopoLoader_Load(session->topo_loader, topology, &resolved_topology, NULL /* FIXME? */);
1575 if (SUCCEEDED(hr))
1577 topology = resolved_topology;
1582 if (flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT)
1584 if ((topology && topology == session->presentation.current_topology) || !topology)
1586 /* FIXME: stop current topology, queue next one. */
1587 session_clear_presentation(session);
1589 else
1590 hr = S_FALSE;
1592 topology = NULL;
1594 else if (topology && flags & MFSESSION_SETTOPOLOGY_IMMEDIATE)
1596 session_clear_queued_topologies(session);
1597 session_clear_presentation(session);
1600 session_raise_topology_set(session, topology, hr);
1602 /* With no current topology set it right away, otherwise queue. */
1603 if (topology)
1605 struct queued_topology *queued_topology;
1607 if ((queued_topology = calloc(1, sizeof(*queued_topology))))
1609 queued_topology->topology = topology;
1610 IMFTopology_AddRef(queued_topology->topology);
1612 list_add_tail(&session->topologies, &queued_topology->entry);
1615 if (session->presentation.topo_status == MF_TOPOSTATUS_INVALID)
1617 hr = session_set_current_topology(session, topology);
1618 session_set_topo_status(session, hr, MF_TOPOSTATUS_READY);
1622 if (resolved_topology)
1623 IMFTopology_Release(resolved_topology);
1626 static HRESULT WINAPI mfsession_QueryInterface(IMFMediaSession *iface, REFIID riid, void **out)
1628 struct media_session *session = impl_from_IMFMediaSession(iface);
1630 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1632 if (IsEqualIID(riid, &IID_IMFMediaSession) ||
1633 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
1634 IsEqualIID(riid, &IID_IUnknown))
1636 *out = &session->IMFMediaSession_iface;
1637 IMFMediaSession_AddRef(iface);
1638 return S_OK;
1640 else if (IsEqualIID(riid, &IID_IMFGetService))
1642 *out = &session->IMFGetService_iface;
1643 IMFMediaSession_AddRef(iface);
1644 return S_OK;
1647 WARN("Unsupported %s.\n", debugstr_guid(riid));
1648 *out = NULL;
1649 return E_NOINTERFACE;
1652 static ULONG WINAPI mfsession_AddRef(IMFMediaSession *iface)
1654 struct media_session *session = impl_from_IMFMediaSession(iface);
1655 ULONG refcount = InterlockedIncrement(&session->refcount);
1657 TRACE("%p, refcount %u.\n", iface, refcount);
1659 return refcount;
1662 static ULONG WINAPI mfsession_Release(IMFMediaSession *iface)
1664 struct media_session *session = impl_from_IMFMediaSession(iface);
1665 ULONG refcount = InterlockedDecrement(&session->refcount);
1667 TRACE("%p, refcount %u.\n", iface, refcount);
1669 if (!refcount)
1671 session_clear_queued_topologies(session);
1672 session_clear_presentation(session);
1673 session_clear_command_list(session);
1674 if (session->presentation.current_topology)
1675 IMFTopology_Release(session->presentation.current_topology);
1676 if (session->event_queue)
1677 IMFMediaEventQueue_Release(session->event_queue);
1678 if (session->clock)
1679 IMFPresentationClock_Release(session->clock);
1680 if (session->system_time_source)
1681 IMFPresentationTimeSource_Release(session->system_time_source);
1682 if (session->clock_rate_control)
1683 IMFRateControl_Release(session->clock_rate_control);
1684 if (session->topo_loader)
1685 IMFTopoLoader_Release(session->topo_loader);
1686 if (session->quality_manager)
1687 IMFQualityManager_Release(session->quality_manager);
1688 DeleteCriticalSection(&session->cs);
1689 free(session);
1692 return refcount;
1695 static HRESULT WINAPI mfsession_GetEvent(IMFMediaSession *iface, DWORD flags, IMFMediaEvent **event)
1697 struct media_session *session = impl_from_IMFMediaSession(iface);
1699 TRACE("%p, %#x, %p.\n", iface, flags, event);
1701 return IMFMediaEventQueue_GetEvent(session->event_queue, flags, event);
1704 static HRESULT WINAPI mfsession_BeginGetEvent(IMFMediaSession *iface, IMFAsyncCallback *callback, IUnknown *state)
1706 struct media_session *session = impl_from_IMFMediaSession(iface);
1708 TRACE("%p, %p, %p.\n", iface, callback, state);
1710 return IMFMediaEventQueue_BeginGetEvent(session->event_queue, callback, state);
1713 static HRESULT WINAPI mfsession_EndGetEvent(IMFMediaSession *iface, IMFAsyncResult *result, IMFMediaEvent **event)
1715 struct media_session *session = impl_from_IMFMediaSession(iface);
1717 TRACE("%p, %p, %p.\n", iface, result, event);
1719 return IMFMediaEventQueue_EndGetEvent(session->event_queue, result, event);
1722 static HRESULT WINAPI mfsession_QueueEvent(IMFMediaSession *iface, MediaEventType event_type, REFGUID ext_type,
1723 HRESULT hr, const PROPVARIANT *value)
1725 struct media_session *session = impl_from_IMFMediaSession(iface);
1727 TRACE("%p, %d, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
1729 return IMFMediaEventQueue_QueueEventParamVar(session->event_queue, event_type, ext_type, hr, value);
1732 static HRESULT WINAPI mfsession_SetTopology(IMFMediaSession *iface, DWORD flags, IMFTopology *topology)
1734 struct media_session *session = impl_from_IMFMediaSession(iface);
1735 struct session_op *op;
1736 WORD node_count = 0;
1737 HRESULT hr;
1739 TRACE("%p, %#x, %p.\n", iface, flags, topology);
1741 if (topology)
1743 if (FAILED(IMFTopology_GetNodeCount(topology, &node_count)) || node_count == 0)
1744 return E_INVALIDARG;
1747 if (FAILED(hr = create_session_op(SESSION_CMD_SET_TOPOLOGY, &op)))
1748 return hr;
1750 op->u.set_topology.flags = flags;
1751 op->u.set_topology.topology = topology;
1752 if (op->u.set_topology.topology)
1753 IMFTopology_AddRef(op->u.set_topology.topology);
1755 hr = session_submit_command(session, op);
1756 IUnknown_Release(&op->IUnknown_iface);
1758 return hr;
1761 static HRESULT WINAPI mfsession_ClearTopologies(IMFMediaSession *iface)
1763 struct media_session *session = impl_from_IMFMediaSession(iface);
1765 TRACE("%p.\n", iface);
1767 return session_submit_simple_command(session, SESSION_CMD_CLEAR_TOPOLOGIES);
1770 static HRESULT WINAPI mfsession_Start(IMFMediaSession *iface, const GUID *format, const PROPVARIANT *start_position)
1772 struct media_session *session = impl_from_IMFMediaSession(iface);
1773 struct session_op *op;
1774 HRESULT hr;
1776 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), start_position);
1778 if (!start_position)
1779 return E_POINTER;
1781 if (FAILED(hr = create_session_op(SESSION_CMD_START, &op)))
1782 return hr;
1784 op->u.start.time_format = format ? *format : GUID_NULL;
1785 hr = PropVariantCopy(&op->u.start.start_position, start_position);
1787 if (SUCCEEDED(hr))
1788 hr = session_submit_command(session, op);
1790 IUnknown_Release(&op->IUnknown_iface);
1791 return hr;
1794 static HRESULT WINAPI mfsession_Pause(IMFMediaSession *iface)
1796 struct media_session *session = impl_from_IMFMediaSession(iface);
1798 TRACE("%p.\n", iface);
1800 return session_submit_simple_command(session, SESSION_CMD_PAUSE);
1803 static HRESULT WINAPI mfsession_Stop(IMFMediaSession *iface)
1805 struct media_session *session = impl_from_IMFMediaSession(iface);
1807 TRACE("%p.\n", iface);
1809 return session_submit_simple_command(session, SESSION_CMD_STOP);
1812 static HRESULT WINAPI mfsession_Close(IMFMediaSession *iface)
1814 struct media_session *session = impl_from_IMFMediaSession(iface);
1816 TRACE("%p.\n", iface);
1818 return session_submit_simple_command(session, SESSION_CMD_CLOSE);
1821 static HRESULT WINAPI mfsession_Shutdown(IMFMediaSession *iface)
1823 struct media_session *session = impl_from_IMFMediaSession(iface);
1824 HRESULT hr = S_OK;
1826 TRACE("%p.\n", iface);
1828 EnterCriticalSection(&session->cs);
1829 if (SUCCEEDED(hr = session_is_shut_down(session)))
1831 session->state = SESSION_STATE_SHUT_DOWN;
1832 IMFMediaEventQueue_Shutdown(session->event_queue);
1833 if (session->quality_manager)
1834 IMFQualityManager_Shutdown(session->quality_manager);
1835 MFShutdownObject((IUnknown *)session->clock);
1836 IMFPresentationClock_Release(session->clock);
1837 session->clock = NULL;
1838 session_clear_presentation(session);
1839 session_clear_command_list(session);
1841 LeaveCriticalSection(&session->cs);
1843 return hr;
1846 static HRESULT WINAPI mfsession_GetClock(IMFMediaSession *iface, IMFClock **clock)
1848 struct media_session *session = impl_from_IMFMediaSession(iface);
1849 HRESULT hr;
1851 TRACE("%p, %p.\n", iface, clock);
1853 EnterCriticalSection(&session->cs);
1854 if (SUCCEEDED(hr = session_is_shut_down(session)))
1856 *clock = (IMFClock *)session->clock;
1857 IMFClock_AddRef(*clock);
1859 LeaveCriticalSection(&session->cs);
1861 return hr;
1864 static HRESULT WINAPI mfsession_GetSessionCapabilities(IMFMediaSession *iface, DWORD *caps)
1866 struct media_session *session = impl_from_IMFMediaSession(iface);
1867 HRESULT hr = S_OK;
1869 TRACE("%p, %p.\n", iface, caps);
1871 if (!caps)
1872 return E_POINTER;
1874 EnterCriticalSection(&session->cs);
1875 if (SUCCEEDED(hr = session_is_shut_down(session)))
1876 *caps = session->caps;
1877 LeaveCriticalSection(&session->cs);
1879 return hr;
1882 static HRESULT WINAPI mfsession_GetFullTopology(IMFMediaSession *iface, DWORD flags, TOPOID id, IMFTopology **topology)
1884 struct media_session *session = impl_from_IMFMediaSession(iface);
1885 struct queued_topology *queued;
1886 TOPOID topo_id;
1887 HRESULT hr;
1889 TRACE("%p, %#x, %s, %p.\n", iface, flags, wine_dbgstr_longlong(id), topology);
1891 *topology = NULL;
1893 EnterCriticalSection(&session->cs);
1895 if (SUCCEEDED(hr = session_is_shut_down(session)))
1897 if (flags & MFSESSION_GETFULLTOPOLOGY_CURRENT)
1899 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
1900 *topology = session->presentation.current_topology;
1901 else
1902 hr = MF_E_INVALIDREQUEST;
1904 else
1906 LIST_FOR_EACH_ENTRY(queued, &session->topologies, struct queued_topology, entry)
1908 if (SUCCEEDED(IMFTopology_GetTopologyID(queued->topology, &topo_id)) && topo_id == id)
1910 *topology = queued->topology;
1911 break;
1916 if (*topology)
1917 IMFTopology_AddRef(*topology);
1920 LeaveCriticalSection(&session->cs);
1922 return hr;
1925 static const IMFMediaSessionVtbl mfmediasessionvtbl =
1927 mfsession_QueryInterface,
1928 mfsession_AddRef,
1929 mfsession_Release,
1930 mfsession_GetEvent,
1931 mfsession_BeginGetEvent,
1932 mfsession_EndGetEvent,
1933 mfsession_QueueEvent,
1934 mfsession_SetTopology,
1935 mfsession_ClearTopologies,
1936 mfsession_Start,
1937 mfsession_Pause,
1938 mfsession_Stop,
1939 mfsession_Close,
1940 mfsession_Shutdown,
1941 mfsession_GetClock,
1942 mfsession_GetSessionCapabilities,
1943 mfsession_GetFullTopology,
1946 static HRESULT WINAPI session_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1948 struct media_session *session = impl_from_IMFGetService(iface);
1949 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
1952 static ULONG WINAPI session_get_service_AddRef(IMFGetService *iface)
1954 struct media_session *session = impl_from_IMFGetService(iface);
1955 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
1958 static ULONG WINAPI session_get_service_Release(IMFGetService *iface)
1960 struct media_session *session = impl_from_IMFGetService(iface);
1961 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
1964 typedef BOOL (*p_renderer_node_test_func)(IMFMediaSink *sink);
1966 static BOOL session_video_renderer_test_func(IMFMediaSink *sink)
1968 IUnknown *obj;
1969 HRESULT hr;
1971 /* Use first sink to support IMFVideoRenderer. */
1972 hr = IMFMediaSink_QueryInterface(sink, &IID_IMFVideoRenderer, (void **)&obj);
1973 if (obj)
1974 IUnknown_Release(obj);
1976 return hr == S_OK;
1979 static BOOL session_audio_renderer_test_func(IMFMediaSink *sink)
1981 return mf_is_sar_sink(sink);
1984 static HRESULT session_get_renderer_node_service(struct media_session *session,
1985 p_renderer_node_test_func node_test_func, REFGUID service, REFIID riid, void **obj)
1987 HRESULT hr = E_NOINTERFACE;
1988 IMFStreamSink *stream_sink;
1989 IMFTopologyNode *node;
1990 IMFCollection *nodes;
1991 IMFMediaSink *sink;
1992 unsigned int i = 0;
1994 if (session->presentation.current_topology)
1996 if (SUCCEEDED(IMFTopology_GetOutputNodeCollection(session->presentation.current_topology,
1997 &nodes)))
1999 while (IMFCollection_GetElement(nodes, i++, (IUnknown **)&node) == S_OK)
2001 if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink)))
2003 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink)))
2005 if (node_test_func(sink))
2007 if (FAILED(hr = MFGetService((IUnknown *)sink, service, riid, obj)))
2008 WARN("Failed to get service from renderer node, %#x.\n", hr);
2011 IMFStreamSink_Release(stream_sink);
2014 IMFTopologyNode_Release(node);
2016 if (*obj)
2017 break;
2020 IMFCollection_Release(nodes);
2024 return hr;
2027 static HRESULT session_get_audio_render_service(struct media_session *session, REFGUID service,
2028 REFIID riid, void **obj)
2030 return session_get_renderer_node_service(session, session_audio_renderer_test_func,
2031 service, riid, obj);
2034 static HRESULT session_get_video_render_service(struct media_session *session, REFGUID service,
2035 REFIID riid, void **obj)
2037 return session_get_renderer_node_service(session, session_video_renderer_test_func,
2038 service, riid, obj);
2041 static HRESULT WINAPI session_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
2043 struct media_session *session = impl_from_IMFGetService(iface);
2044 HRESULT hr = S_OK;
2046 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
2048 *obj = NULL;
2050 EnterCriticalSection(&session->cs);
2051 if (FAILED(hr = session_is_shut_down(session)))
2054 else if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE))
2056 if (IsEqualIID(riid, &IID_IMFRateSupport))
2058 *obj = &session->IMFRateSupport_iface;
2060 else if (IsEqualIID(riid, &IID_IMFRateControl))
2062 *obj = &session->IMFRateControl_iface;
2064 else
2065 hr = E_NOINTERFACE;
2067 if (*obj)
2068 IUnknown_AddRef((IUnknown *)*obj);
2070 else if (IsEqualGUID(service, &MF_LOCAL_MFT_REGISTRATION_SERVICE))
2072 hr = IMFLocalMFTRegistration_QueryInterface(&local_mft_registration, riid, obj);
2074 else if (IsEqualGUID(service, &MF_TOPONODE_ATTRIBUTE_EDITOR_SERVICE))
2076 *obj = &session->IMFTopologyNodeAttributeEditor_iface;
2077 IUnknown_AddRef((IUnknown *)*obj);
2079 else if (IsEqualGUID(service, &MR_VIDEO_RENDER_SERVICE))
2081 hr = session_get_video_render_service(session, service, riid, obj);
2083 else if (IsEqualGUID(service, &MR_POLICY_VOLUME_SERVICE))
2085 hr = session_get_audio_render_service(session, service, riid, obj);
2087 else
2088 FIXME("Unsupported service %s.\n", debugstr_guid(service));
2090 LeaveCriticalSection(&session->cs);
2092 return hr;
2095 static const IMFGetServiceVtbl session_get_service_vtbl =
2097 session_get_service_QueryInterface,
2098 session_get_service_AddRef,
2099 session_get_service_Release,
2100 session_get_service_GetService,
2103 static HRESULT WINAPI session_commands_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
2105 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
2106 IsEqualIID(riid, &IID_IUnknown))
2108 *obj = iface;
2109 IMFAsyncCallback_AddRef(iface);
2110 return S_OK;
2113 WARN("Unsupported %s.\n", debugstr_guid(riid));
2114 *obj = NULL;
2115 return E_NOINTERFACE;
2118 static ULONG WINAPI session_commands_callback_AddRef(IMFAsyncCallback *iface)
2120 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2121 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2124 static ULONG WINAPI session_commands_callback_Release(IMFAsyncCallback *iface)
2126 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2127 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2130 static HRESULT WINAPI session_commands_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
2132 return E_NOTIMPL;
2135 static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
2137 struct session_op *op = impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result));
2138 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2139 struct topo_node *topo_node;
2140 IMFTopologyNode *upstream_node;
2141 unsigned int upstream_output;
2143 EnterCriticalSection(&session->cs);
2145 switch (op->command)
2147 case SESSION_CMD_CLEAR_TOPOLOGIES:
2148 session_clear_topologies(session);
2149 break;
2150 case SESSION_CMD_SET_TOPOLOGY:
2151 session_set_topology(session, op->u.set_topology.flags, op->u.set_topology.topology);
2152 session_command_complete(session);
2153 break;
2154 case SESSION_CMD_START:
2155 session_start(session, &op->u.start.time_format, &op->u.start.start_position);
2156 break;
2157 case SESSION_CMD_PAUSE:
2158 session_pause(session);
2159 break;
2160 case SESSION_CMD_STOP:
2161 session_stop(session);
2162 break;
2163 case SESSION_CMD_CLOSE:
2164 session_close(session);
2165 break;
2166 case SESSION_CMD_QM_NOTIFY_TOPOLOGY:
2167 IMFQualityManager_NotifyTopology(session->quality_manager, op->u.notify_topology.topology);
2168 session_command_complete(session);
2169 break;
2170 case SESSION_CMD_SA_READY:
2171 topo_node = session_get_node_by_id(session, op->u.sa_ready.node_id);
2173 if (topo_node->u.sink.requests)
2175 if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node->node, 0, &upstream_node, &upstream_output)))
2177 session_request_sample_from_node(session, upstream_node, upstream_output);
2178 IMFTopologyNode_Release(upstream_node);
2181 break;
2182 default:
2186 LeaveCriticalSection(&session->cs);
2188 return S_OK;
2191 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl =
2193 session_commands_callback_QueryInterface,
2194 session_commands_callback_AddRef,
2195 session_commands_callback_Release,
2196 session_commands_callback_GetParameters,
2197 session_commands_callback_Invoke,
2200 static HRESULT WINAPI session_events_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
2202 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
2203 IsEqualIID(riid, &IID_IUnknown))
2205 *obj = iface;
2206 IMFAsyncCallback_AddRef(iface);
2207 return S_OK;
2210 WARN("Unsupported %s.\n", debugstr_guid(riid));
2211 *obj = NULL;
2212 return E_NOINTERFACE;
2215 static ULONG WINAPI session_events_callback_AddRef(IMFAsyncCallback *iface)
2217 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
2218 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2221 static ULONG WINAPI session_events_callback_Release(IMFAsyncCallback *iface)
2223 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
2224 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2227 static HRESULT WINAPI session_events_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
2229 return E_NOTIMPL;
2232 static HRESULT session_add_media_stream(struct media_session *session, IMFMediaSource *source, IMFMediaStream *stream)
2234 struct topo_node *node;
2235 IMFStreamDescriptor *sd;
2236 DWORD stream_id = 0;
2237 HRESULT hr;
2239 if (FAILED(hr = IMFMediaStream_GetStreamDescriptor(stream, &sd)))
2240 return hr;
2242 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &stream_id);
2243 IMFStreamDescriptor_Release(sd);
2244 if (FAILED(hr))
2245 return hr;
2247 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2249 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->u.source.source == source
2250 && node->u.source.stream_id == stream_id)
2252 if (node->object.source_stream)
2254 WARN("Node already has stream set.\n");
2255 return S_FALSE;
2258 node->object.source_stream = stream;
2259 IMFMediaStream_AddRef(node->object.source_stream);
2260 break;
2264 return S_OK;
2267 static BOOL session_is_source_nodes_state(struct media_session *session, enum object_state state)
2269 struct media_source *source;
2270 struct topo_node *node;
2272 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2274 if (source->state != state)
2275 return FALSE;
2278 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2280 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->state != state)
2281 return FALSE;
2284 return TRUE;
2287 static BOOL session_is_output_nodes_state(struct media_session *session, enum object_state state)
2289 struct topo_node *node;
2291 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2293 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->state != state)
2294 return FALSE;
2297 return TRUE;
2300 static enum object_state session_get_object_state_for_event(MediaEventType event)
2302 switch (event)
2304 case MESourceStarted:
2305 case MEStreamStarted:
2306 case MEStreamSinkStarted:
2307 return OBJ_STATE_STARTED;
2308 case MESourcePaused:
2309 case MEStreamPaused:
2310 case MEStreamSinkPaused:
2311 return OBJ_STATE_PAUSED;
2312 case MESourceStopped:
2313 case MEStreamStopped:
2314 case MEStreamSinkStopped:
2315 return OBJ_STATE_STOPPED;
2316 case MEStreamSinkPrerolled:
2317 return OBJ_STATE_PREROLLED;
2318 default:
2319 return OBJ_STATE_INVALID;
2323 static void session_set_consumed_clock(IUnknown *object, IMFPresentationClock *clock)
2325 IMFClockConsumer *consumer;
2327 if (SUCCEEDED(IUnknown_QueryInterface(object, &IID_IMFClockConsumer, (void **)&consumer)))
2329 IMFClockConsumer_SetPresentationClock(consumer, clock);
2330 IMFClockConsumer_Release(consumer);
2334 static void session_set_presentation_clock(struct media_session *session)
2336 IMFPresentationTimeSource *time_source = NULL;
2337 struct media_source *source;
2338 struct media_sink *sink;
2339 struct topo_node *node;
2340 HRESULT hr;
2342 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2344 if (node->type == MF_TOPOLOGY_TRANSFORM_NODE)
2345 IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
2348 if (!(session->presentation.flags & SESSION_FLAG_PRESENTATION_CLOCK_SET))
2350 /* Attempt to get time source from the sinks. */
2351 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2353 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink->sink, &IID_IMFPresentationTimeSource,
2354 (void **)&time_source)))
2355 break;
2358 if (time_source)
2360 hr = IMFPresentationClock_SetTimeSource(session->clock, time_source);
2361 IMFPresentationTimeSource_Release(time_source);
2363 else
2364 hr = IMFPresentationClock_SetTimeSource(session->clock, session->system_time_source);
2366 if (FAILED(hr))
2367 WARN("Failed to set time source, hr %#x.\n", hr);
2369 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2371 if (node->type != MF_TOPOLOGY_OUTPUT_NODE)
2372 continue;
2374 if (FAILED(hr = IMFStreamSink_BeginGetEvent(node->object.sink_stream, &session->events_callback,
2375 node->object.object)))
2377 WARN("Failed to subscribe to stream sink events, hr %#x.\n", hr);
2381 /* Set clock for all topology nodes. */
2382 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2384 session_set_consumed_clock((IUnknown *)source->source, session->clock);
2387 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2389 if (sink->event_generator && FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(sink->event_generator,
2390 &session->events_callback, (IUnknown *)sink->event_generator)))
2392 WARN("Failed to subscribe to sink events, hr %#x.\n", hr);
2395 if (FAILED(hr = IMFMediaSink_SetPresentationClock(sink->sink, session->clock)))
2396 WARN("Failed to set presentation clock for the sink, hr %#x.\n", hr);
2399 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2401 if (node->type != MF_TOPOLOGY_TRANSFORM_NODE)
2402 continue;
2404 session_set_consumed_clock(node->object.object, session->clock);
2407 session->presentation.flags |= SESSION_FLAG_PRESENTATION_CLOCK_SET;
2411 static HRESULT session_start_clock(struct media_session *session)
2413 LONGLONG start_offset = 0;
2414 HRESULT hr;
2416 if (IsEqualGUID(&session->presentation.time_format, &GUID_NULL))
2418 if (session->presentation.start_position.vt == VT_EMPTY)
2419 start_offset = PRESENTATION_CURRENT_POSITION;
2420 else if (session->presentation.start_position.vt == VT_I8)
2421 start_offset = session->presentation.start_position.hVal.QuadPart;
2422 else
2423 FIXME("Unhandled position type %d.\n", session->presentation.start_position.vt);
2425 else
2426 FIXME("Unhandled time format %s.\n", debugstr_guid(&session->presentation.time_format));
2428 if (FAILED(hr = IMFPresentationClock_Start(session->clock, start_offset)))
2429 WARN("Failed to start session clock, hr %#x.\n", hr);
2431 return hr;
2434 static struct topo_node *session_get_node_object(struct media_session *session, IUnknown *object,
2435 MF_TOPOLOGY_TYPE node_type)
2437 struct topo_node *node = NULL;
2439 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2441 if (node->type == node_type && object == node->object.object)
2442 break;
2445 return node;
2448 static BOOL session_set_node_object_state(struct media_session *session, IUnknown *object,
2449 MF_TOPOLOGY_TYPE node_type, enum object_state state)
2451 struct topo_node *node;
2452 BOOL changed = FALSE;
2454 if ((node = session_get_node_object(session, object, node_type)))
2456 changed = node->state != state;
2457 node->state = state;
2460 return changed;
2463 static void session_set_source_object_state(struct media_session *session, IUnknown *object,
2464 MediaEventType event_type)
2466 IMFStreamSink *stream_sink;
2467 struct media_source *src;
2468 struct media_sink *sink;
2469 enum object_state state;
2470 struct topo_node *node;
2471 unsigned int i, count;
2472 BOOL changed = FALSE;
2473 HRESULT hr;
2475 if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
2476 return;
2478 switch (event_type)
2480 case MESourceStarted:
2481 case MESourcePaused:
2482 case MESourceStopped:
2484 LIST_FOR_EACH_ENTRY(src, &session->presentation.sources, struct media_source, entry)
2486 if (object == (IUnknown *)src->source)
2488 changed = src->state != state;
2489 src->state = state;
2490 break;
2493 break;
2494 case MEStreamStarted:
2495 case MEStreamPaused:
2496 case MEStreamStopped:
2498 changed = session_set_node_object_state(session, object, MF_TOPOLOGY_SOURCESTREAM_NODE, state);
2499 default:
2503 if (!changed)
2504 return;
2506 switch (session->state)
2508 case SESSION_STATE_STARTING_SOURCES:
2509 if (!session_is_source_nodes_state(session, OBJ_STATE_STARTED))
2510 break;
2512 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_STARTED_SOURCE);
2514 session_set_presentation_clock(session);
2516 if (session->presentation.flags & SESSION_FLAG_NEEDS_PREROLL)
2518 MFTIME preroll_time = 0;
2520 if (session->presentation.start_position.vt == VT_I8)
2521 preroll_time = session->presentation.start_position.hVal.QuadPart;
2523 /* Mark stream sinks without prerolling support as PREROLLED to keep state test logic generic. */
2524 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2526 if (sink->preroll)
2528 /* FIXME: abort and enter error state on failure. */
2529 if (FAILED(hr = IMFMediaSinkPreroll_NotifyPreroll(sink->preroll, preroll_time)))
2530 WARN("Preroll notification failed, hr %#x.\n", hr);
2532 else
2534 if (SUCCEEDED(IMFMediaSink_GetStreamSinkCount(sink->sink, &count)))
2536 for (i = 0; i < count; ++i)
2538 if (SUCCEEDED(IMFMediaSink_GetStreamSinkByIndex(sink->sink, i, &stream_sink)))
2540 session_set_node_object_state(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE,
2541 OBJ_STATE_PREROLLED);
2542 IMFStreamSink_Release(stream_sink);
2548 session->state = SESSION_STATE_PREROLLING_SINKS;
2550 else if (SUCCEEDED(session_start_clock(session)))
2551 session->state = SESSION_STATE_STARTING_SINKS;
2553 break;
2554 case SESSION_STATE_PAUSING_SOURCES:
2555 if (!session_is_source_nodes_state(session, OBJ_STATE_PAUSED))
2556 break;
2558 session_set_paused(session, SESSION_STATE_PAUSED, S_OK);
2559 break;
2560 case SESSION_STATE_STOPPING_SOURCES:
2561 if (!session_is_source_nodes_state(session, OBJ_STATE_STOPPED))
2562 break;
2564 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2566 switch (node->type)
2568 case MF_TOPOLOGY_OUTPUT_NODE:
2569 IMFStreamSink_Flush(node->object.sink_stream);
2570 break;
2571 case MF_TOPOLOGY_TRANSFORM_NODE:
2572 IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_COMMAND_FLUSH, 0);
2573 break;
2574 default:
2579 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
2581 if (session->presentation.flags & SESSION_FLAG_FINALIZE_SINKS)
2582 session_finalize_sinks(session);
2583 else
2584 session_set_stopped(session, S_OK);
2586 break;
2587 default:
2592 static void session_set_sink_stream_state(struct media_session *session, IMFStreamSink *stream,
2593 MediaEventType event_type)
2595 struct media_source *source;
2596 enum object_state state;
2597 HRESULT hr = S_OK;
2598 BOOL changed;
2600 if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
2601 return;
2603 if (!(changed = session_set_node_object_state(session, (IUnknown *)stream, MF_TOPOLOGY_OUTPUT_NODE, state)))
2604 return;
2606 switch (session->state)
2608 case SESSION_STATE_PREROLLING_SINKS:
2609 if (!session_is_output_nodes_state(session, OBJ_STATE_PREROLLED))
2610 break;
2612 if (SUCCEEDED(session_start_clock(session)))
2613 session->state = SESSION_STATE_STARTING_SINKS;
2614 break;
2615 case SESSION_STATE_STARTING_SINKS:
2616 if (!session_is_output_nodes_state(session, OBJ_STATE_STARTED))
2617 break;
2619 session_set_started(session);
2620 break;
2621 case SESSION_STATE_PAUSING_SINKS:
2622 if (!session_is_output_nodes_state(session, OBJ_STATE_PAUSED))
2623 break;
2625 session->state = SESSION_STATE_PAUSING_SOURCES;
2627 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2629 if (FAILED(hr = IMFMediaSource_Pause(source->source)))
2630 break;
2633 if (FAILED(hr))
2634 session_set_paused(session, SESSION_STATE_PAUSED, hr);
2636 break;
2637 case SESSION_STATE_STOPPING_SINKS:
2638 if (!session_is_output_nodes_state(session, OBJ_STATE_STOPPED))
2639 break;
2641 session->state = SESSION_STATE_STOPPING_SOURCES;
2643 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2645 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION)
2646 IMFMediaSource_Stop(source->source);
2647 else if (FAILED(hr = IMFMediaSource_Stop(source->source)))
2648 break;
2651 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION || FAILED(hr))
2652 session_set_stopped(session, hr);
2654 break;
2655 default:
2660 static struct sample *transform_create_sample(IMFSample *sample)
2662 struct sample *sample_entry = calloc(1, sizeof(*sample_entry));
2664 if (sample_entry)
2666 sample_entry->sample = sample;
2667 if (sample_entry->sample)
2668 IMFSample_AddRef(sample_entry->sample);
2671 return sample_entry;
2674 static HRESULT transform_get_external_output_sample(const struct media_session *session, struct topo_node *transform,
2675 unsigned int output_index, const MFT_OUTPUT_STREAM_INFO *stream_info, IMFSample **sample)
2677 unsigned int buffer_size, downstream_input;
2678 IMFTopologyNode *downstream_node;
2679 IMFMediaBuffer *buffer = NULL;
2680 struct topo_node *topo_node;
2681 TOPOID node_id;
2682 HRESULT hr;
2684 if (FAILED(IMFTopologyNode_GetOutput(transform->node, output_index, &downstream_node, &downstream_input)))
2686 WARN("Failed to get connected node for output %u.\n", output_index);
2687 return MF_E_UNEXPECTED;
2690 IMFTopologyNode_GetTopoNodeID(downstream_node, &node_id);
2691 IMFTopologyNode_Release(downstream_node);
2693 topo_node = session_get_node_by_id(session, node_id);
2695 if (topo_node->type == MF_TOPOLOGY_OUTPUT_NODE && topo_node->u.sink.allocator)
2697 hr = IMFVideoSampleAllocator_AllocateSample(topo_node->u.sink.allocator, sample);
2699 else
2701 buffer_size = max(stream_info->cbSize, transform->u.transform.outputs[output_index].min_buffer_size);
2703 hr = MFCreateAlignedMemoryBuffer(buffer_size, stream_info->cbAlignment, &buffer);
2704 if (SUCCEEDED(hr))
2705 hr = MFCreateSample(sample);
2707 if (SUCCEEDED(hr))
2708 hr = IMFSample_AddBuffer(*sample, buffer);
2710 if (buffer)
2711 IMFMediaBuffer_Release(buffer);
2714 return hr;
2717 static HRESULT transform_node_pull_samples(const struct media_session *session, struct topo_node *node)
2719 MFT_OUTPUT_STREAM_INFO stream_info;
2720 MFT_OUTPUT_DATA_BUFFER *buffers;
2721 struct sample *queued_sample;
2722 DWORD status = 0;
2723 unsigned int i;
2724 HRESULT hr = E_UNEXPECTED;
2726 if (!(buffers = calloc(node->u.transform.output_count, sizeof(*buffers))))
2727 return E_OUTOFMEMORY;
2729 for (i = 0; i < node->u.transform.output_count; ++i)
2731 buffers[i].dwStreamID = transform_node_get_stream_id(node, TRUE, i);
2732 buffers[i].pSample = NULL;
2733 buffers[i].dwStatus = 0;
2734 buffers[i].pEvents = NULL;
2736 memset(&stream_info, 0, sizeof(stream_info));
2737 if (FAILED(hr = IMFTransform_GetOutputStreamInfo(node->object.transform, buffers[i].dwStreamID, &stream_info)))
2738 break;
2740 if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)))
2742 if (FAILED(hr = transform_get_external_output_sample(session, node, i, &stream_info, &buffers[i].pSample)))
2743 break;
2747 if (SUCCEEDED(hr))
2748 hr = IMFTransform_ProcessOutput(node->object.transform, 0, node->u.transform.output_count, buffers, &status);
2750 /* Collect returned samples for all streams. */
2751 for (i = 0; i < node->u.transform.output_count; ++i)
2753 if (buffers[i].pEvents)
2754 IMFCollection_Release(buffers[i].pEvents);
2756 if (SUCCEEDED(hr) && !(buffers[i].dwStatus & MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE))
2758 if (session->quality_manager)
2759 IMFQualityManager_NotifyProcessOutput(session->quality_manager, node->node, i, buffers[i].pSample);
2761 queued_sample = transform_create_sample(buffers[i].pSample);
2762 list_add_tail(&node->u.transform.outputs[i].samples, &queued_sample->entry);
2765 if (buffers[i].pSample)
2766 IMFSample_Release(buffers[i].pSample);
2769 free(buffers);
2771 return hr;
2774 static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input,
2775 IMFSample *sample)
2777 struct sample *sample_entry, *sample_entry2;
2778 DWORD stream_id, downstream_input;
2779 IMFTopologyNode *downstream_node;
2780 struct topo_node *topo_node;
2781 MF_TOPOLOGY_TYPE node_type;
2782 BOOL drain = FALSE;
2783 TOPOID node_id;
2784 unsigned int i;
2785 HRESULT hr;
2787 if (session->quality_manager)
2788 IMFQualityManager_NotifyProcessInput(session->quality_manager, node, input, sample);
2790 IMFTopologyNode_GetNodeType(node, &node_type);
2791 IMFTopologyNode_GetTopoNodeID(node, &node_id);
2793 topo_node = session_get_node_by_id(session, node_id);
2795 switch (node_type)
2797 case MF_TOPOLOGY_OUTPUT_NODE:
2798 if (sample)
2800 if (topo_node->u.sink.requests)
2802 if (FAILED(hr = IMFStreamSink_ProcessSample(topo_node->object.sink_stream, sample)))
2803 WARN("Stream sink failed to process sample, hr %#x.\n", hr);
2804 topo_node->u.sink.requests--;
2807 else if (FAILED(hr = IMFStreamSink_PlaceMarker(topo_node->object.sink_stream, MFSTREAMSINK_MARKER_ENDOFSEGMENT,
2808 NULL, NULL)))
2810 WARN("Failed to place sink marker, hr %#x.\n", hr);
2812 break;
2813 case MF_TOPOLOGY_TRANSFORM_NODE:
2815 transform_node_pull_samples(session, topo_node);
2817 sample_entry = transform_create_sample(sample);
2818 list_add_tail(&topo_node->u.transform.inputs[input].samples, &sample_entry->entry);
2820 for (i = 0; i < topo_node->u.transform.input_count; ++i)
2822 stream_id = transform_node_get_stream_id(topo_node, FALSE, i);
2823 LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.inputs[i].samples,
2824 struct sample, entry)
2826 if (sample_entry->sample)
2828 if ((hr = IMFTransform_ProcessInput(topo_node->object.transform, stream_id,
2829 sample_entry->sample, 0)) == MF_E_NOTACCEPTING)
2830 break;
2831 if (FAILED(hr))
2832 WARN("Failed to process input for stream %u/%u, hr %#x.\n", i, stream_id, hr);
2833 transform_release_sample(sample_entry);
2835 else
2837 transform_stream_drop_samples(&topo_node->u.transform.inputs[i]);
2838 drain = TRUE;
2843 if (drain)
2845 if (FAILED(hr = IMFTransform_ProcessMessage(topo_node->object.transform, MFT_MESSAGE_COMMAND_DRAIN, 0)))
2846 WARN("Drain command failed for transform, hr %#x.\n", hr);
2849 transform_node_pull_samples(session, topo_node);
2851 /* Remaining unprocessed input has been discarded, now queue markers for every output. */
2852 if (drain)
2854 for (i = 0; i < topo_node->u.transform.output_count; ++i)
2856 if ((sample_entry = transform_create_sample(NULL)))
2857 list_add_tail(&topo_node->u.transform.outputs[i].samples, &sample_entry->entry);
2861 /* Push down all available output. */
2862 for (i = 0; i < topo_node->u.transform.output_count; ++i)
2864 if (FAILED(IMFTopologyNode_GetOutput(node, i, &downstream_node, &downstream_input)))
2866 WARN("Failed to get connected node for output %u.\n", i);
2867 continue;
2870 LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.outputs[i].samples,
2871 struct sample, entry)
2873 if (!topo_node->u.transform.outputs[i].requests)
2874 break;
2876 session_deliver_sample_to_node(session, downstream_node, downstream_input, sample_entry->sample);
2877 topo_node->u.transform.outputs[i].requests--;
2879 transform_release_sample(sample_entry);
2882 IMFTopologyNode_Release(downstream_node);
2885 break;
2886 case MF_TOPOLOGY_TEE_NODE:
2887 FIXME("Unhandled downstream node type %d.\n", node_type);
2888 break;
2889 default:
2894 static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output)
2896 IMFTopologyNode *downstream_node, *upstream_node;
2897 unsigned int downstream_input, upstream_output;
2898 struct topo_node *topo_node;
2899 MF_TOPOLOGY_TYPE node_type;
2900 struct sample *sample;
2901 TOPOID node_id;
2902 HRESULT hr;
2904 IMFTopologyNode_GetNodeType(node, &node_type);
2905 IMFTopologyNode_GetTopoNodeID(node, &node_id);
2907 topo_node = session_get_node_by_id(session, node_id);
2909 switch (node_type)
2911 case MF_TOPOLOGY_SOURCESTREAM_NODE:
2912 if (FAILED(hr = IMFMediaStream_RequestSample(topo_node->object.source_stream, NULL)))
2913 WARN("Sample request failed, hr %#x.\n", hr);
2914 break;
2915 case MF_TOPOLOGY_TRANSFORM_NODE:
2917 if (list_empty(&topo_node->u.transform.outputs[output].samples))
2919 /* Forward request to upstream node. */
2920 if (SUCCEEDED(hr = IMFTopologyNode_GetInput(node, 0 /* FIXME */, &upstream_node, &upstream_output)))
2922 if (SUCCEEDED(hr = session_request_sample_from_node(session, upstream_node, upstream_output)))
2923 topo_node->u.transform.outputs[output].requests++;
2924 IMFTopologyNode_Release(upstream_node);
2927 else
2929 if (SUCCEEDED(hr = IMFTopologyNode_GetOutput(node, output, &downstream_node, &downstream_input)))
2931 sample = LIST_ENTRY(list_head(&topo_node->u.transform.outputs[output].samples), struct sample, entry);
2932 session_deliver_sample_to_node(session, downstream_node, downstream_input, sample->sample);
2933 transform_release_sample(sample);
2934 IMFTopologyNode_Release(downstream_node);
2938 break;
2939 case MF_TOPOLOGY_TEE_NODE:
2940 FIXME("Unhandled upstream node type %d.\n", node_type);
2941 default:
2942 hr = E_UNEXPECTED;
2945 return hr;
2948 static void session_request_sample(struct media_session *session, IMFStreamSink *sink_stream)
2950 struct topo_node *sink_node = NULL, *node;
2951 IMFTopologyNode *upstream_node;
2952 DWORD upstream_output;
2953 HRESULT hr;
2955 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2957 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink_stream)
2959 sink_node = node;
2960 break;
2964 if (!sink_node)
2965 return;
2967 if (FAILED(hr = IMFTopologyNode_GetInput(sink_node->node, 0, &upstream_node, &upstream_output)))
2969 WARN("Failed to get upstream node connection, hr %#x.\n", hr);
2970 return;
2973 if (SUCCEEDED(session_request_sample_from_node(session, upstream_node, upstream_output)))
2974 sink_node->u.sink.requests++;
2975 IMFTopologyNode_Release(upstream_node);
2978 static void session_deliver_sample(struct media_session *session, IMFMediaStream *stream, const PROPVARIANT *value)
2980 struct topo_node *source_node = NULL, *node;
2981 IMFTopologyNode *downstream_node;
2982 DWORD downstream_input;
2983 HRESULT hr;
2985 if (value && (value->vt != VT_UNKNOWN || !value->punkVal))
2987 WARN("Unexpected value type %d.\n", value->vt);
2988 return;
2991 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2993 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->object.source_stream == stream)
2995 source_node = node;
2996 break;
3000 if (!source_node)
3001 return;
3003 if (!value)
3004 source_node->flags |= TOPO_NODE_END_OF_STREAM;
3006 if (FAILED(hr = IMFTopologyNode_GetOutput(source_node->node, 0, &downstream_node, &downstream_input)))
3008 WARN("Failed to get downstream node connection, hr %#x.\n", hr);
3009 return;
3012 session_deliver_sample_to_node(session, downstream_node, downstream_input, value ? (IMFSample *)value->punkVal : NULL);
3013 IMFTopologyNode_Release(downstream_node);
3016 static void session_sink_invalidated(struct media_session *session, IMFMediaEvent *event, IMFStreamSink *sink)
3018 struct topo_node *node, *sink_node = NULL;
3019 HRESULT hr;
3021 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
3023 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink)
3025 sink_node = node;
3026 break;
3030 if (!sink_node)
3031 return;
3033 if (!event)
3035 if (FAILED(hr = MFCreateMediaEvent(MESinkInvalidated, &GUID_NULL, S_OK, NULL, &event)))
3036 WARN("Failed to create event, hr %#x.\n", hr);
3039 if (!event)
3040 return;
3042 IMFMediaEvent_SetUINT64(event, &MF_EVENT_OUTPUT_NODE, sink_node->node_id);
3043 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3045 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED);
3048 static BOOL session_nodes_is_mask_set(struct media_session *session, MF_TOPOLOGY_TYPE node_type, unsigned int flags)
3050 struct media_source *source;
3051 struct topo_node *node;
3053 if (node_type == MF_TOPOLOGY_MAX)
3055 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3057 if ((source->flags & flags) != flags)
3058 return FALSE;
3061 else
3063 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
3065 if (node->type == node_type && (node->flags & flags) != flags)
3066 return FALSE;
3070 return TRUE;
3073 static void session_raise_end_of_presentation(struct media_session *session)
3075 if (!(session_nodes_is_mask_set(session, MF_TOPOLOGY_SOURCESTREAM_NODE, TOPO_NODE_END_OF_STREAM)))
3076 return;
3078 if (!(session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION))
3080 if (session_nodes_is_mask_set(session, MF_TOPOLOGY_MAX, SOURCE_FLAG_END_OF_PRESENTATION))
3082 session->presentation.flags |= SESSION_FLAG_END_OF_PRESENTATION;
3083 session_push_back_command(session, SESSION_CMD_END);
3084 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, NULL);
3089 static void session_handle_end_of_stream(struct media_session *session, IMFMediaStream *stream)
3091 struct topo_node *node;
3093 if (!(node = session_get_node_object(session, (IUnknown *)stream, MF_TOPOLOGY_SOURCESTREAM_NODE))
3094 || node->flags & TOPO_NODE_END_OF_STREAM)
3096 return;
3099 session_deliver_sample(session, stream, NULL);
3101 session_raise_end_of_presentation(session);
3104 static void session_handle_end_of_presentation(struct media_session *session, IMFMediaSource *object)
3106 struct media_source *source;
3108 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3110 if (source->source == object)
3112 if (!(source->flags & SOURCE_FLAG_END_OF_PRESENTATION))
3114 source->flags |= SOURCE_FLAG_END_OF_PRESENTATION;
3115 session_raise_end_of_presentation(session);
3118 break;
3123 static void session_sink_stream_marker(struct media_session *session, IMFStreamSink *stream_sink)
3125 struct topo_node *node;
3127 if (!(node = session_get_node_object(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE))
3128 || node->flags & TOPO_NODE_END_OF_STREAM)
3130 return;
3133 node->flags |= TOPO_NODE_END_OF_STREAM;
3135 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION &&
3136 session_nodes_is_mask_set(session, MF_TOPOLOGY_OUTPUT_NODE, TOPO_NODE_END_OF_STREAM))
3138 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED);
3139 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
3140 session_stop(session);
3144 static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
3146 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
3147 IMFMediaEventGenerator *event_source;
3148 IMFMediaEvent *event = NULL;
3149 MediaEventType event_type;
3150 IUnknown *object = NULL;
3151 IMFMediaSource *source;
3152 IMFMediaStream *stream;
3153 PROPVARIANT value;
3154 HRESULT hr;
3156 if (FAILED(hr = IMFAsyncResult_GetState(result, (IUnknown **)&event_source)))
3157 return hr;
3159 if (FAILED(hr = IMFMediaEventGenerator_EndGetEvent(event_source, result, &event)))
3161 WARN("Failed to get event from %p, hr %#x.\n", event_source, hr);
3162 goto failed;
3165 if (FAILED(hr = IMFMediaEvent_GetType(event, &event_type)))
3167 WARN("Failed to get event type, hr %#x.\n", hr);
3168 goto failed;
3171 value.vt = VT_EMPTY;
3172 if (FAILED(hr = IMFMediaEvent_GetValue(event, &value)))
3174 WARN("Failed to get event value, hr %#x.\n", hr);
3175 goto failed;
3178 switch (event_type)
3180 case MESourceStarted:
3181 case MESourcePaused:
3182 case MESourceStopped:
3183 case MEStreamStarted:
3184 case MEStreamPaused:
3185 case MEStreamStopped:
3187 EnterCriticalSection(&session->cs);
3188 session_set_source_object_state(session, (IUnknown *)event_source, event_type);
3189 LeaveCriticalSection(&session->cs);
3191 break;
3193 case MEBufferingStarted:
3194 case MEBufferingStopped:
3196 EnterCriticalSection(&session->cs);
3197 if (session_get_media_source(session, (IMFMediaSource *)event_source))
3199 if (event_type == MEBufferingStarted)
3200 IMFPresentationClock_Pause(session->clock);
3201 else
3202 IMFPresentationClock_Start(session->clock, PRESENTATION_CURRENT_POSITION);
3204 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3206 LeaveCriticalSection(&session->cs);
3207 break;
3209 case MEReconnectStart:
3210 case MEReconnectEnd:
3212 EnterCriticalSection(&session->cs);
3213 if (session_get_media_source(session, (IMFMediaSource *)event_source))
3214 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3215 LeaveCriticalSection(&session->cs);
3216 break;
3218 case MEExtendedType:
3219 case MERendererEvent:
3220 case MEStreamSinkFormatChanged:
3222 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3223 break;
3225 case MENewStream:
3226 stream = (IMFMediaStream *)value.punkVal;
3228 if (value.vt != VT_UNKNOWN || !stream)
3230 WARN("Unexpected event value.\n");
3231 break;
3234 if (FAILED(hr = IMFMediaStream_GetMediaSource(stream, &source)))
3235 break;
3237 EnterCriticalSection(&session->cs);
3238 if (SUCCEEDED(hr = session_add_media_stream(session, source, stream)))
3239 hr = IMFMediaStream_BeginGetEvent(stream, &session->events_callback, (IUnknown *)stream);
3240 LeaveCriticalSection(&session->cs);
3242 IMFMediaSource_Release(source);
3244 break;
3245 case MEStreamSinkStarted:
3246 case MEStreamSinkPaused:
3247 case MEStreamSinkStopped:
3248 case MEStreamSinkPrerolled:
3250 EnterCriticalSection(&session->cs);
3251 session_set_sink_stream_state(session, (IMFStreamSink *)event_source, event_type);
3252 LeaveCriticalSection(&session->cs);
3254 break;
3255 case MEStreamSinkMarker:
3257 EnterCriticalSection(&session->cs);
3258 session_sink_stream_marker(session, (IMFStreamSink *)event_source);
3259 LeaveCriticalSection(&session->cs);
3261 break;
3262 case MEStreamSinkRequestSample:
3264 EnterCriticalSection(&session->cs);
3265 session_request_sample(session, (IMFStreamSink *)event_source);
3266 LeaveCriticalSection(&session->cs);
3268 break;
3269 case MEMediaSample:
3271 EnterCriticalSection(&session->cs);
3272 session_deliver_sample(session, (IMFMediaStream *)event_source, &value);
3273 LeaveCriticalSection(&session->cs);
3275 break;
3276 case MEEndOfStream:
3278 EnterCriticalSection(&session->cs);
3279 session_handle_end_of_stream(session, (IMFMediaStream *)event_source);
3280 LeaveCriticalSection(&session->cs);
3282 break;
3284 case MEEndOfPresentation:
3286 EnterCriticalSection(&session->cs);
3287 session_handle_end_of_presentation(session, (IMFMediaSource *)event_source);
3288 LeaveCriticalSection(&session->cs);
3290 break;
3291 case MEAudioSessionGroupingParamChanged:
3292 case MEAudioSessionIconChanged:
3293 case MEAudioSessionNameChanged:
3294 case MEAudioSessionVolumeChanged:
3296 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3298 break;
3299 case MEAudioSessionDeviceRemoved:
3300 case MEAudioSessionDisconnected:
3301 case MEAudioSessionExclusiveModeOverride:
3302 case MEAudioSessionFormatChanged:
3303 case MEAudioSessionServerShutdown:
3305 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3306 /* fallthrough */
3307 case MESinkInvalidated:
3309 EnterCriticalSection(&session->cs);
3310 session_sink_invalidated(session, event_type == MESinkInvalidated ? event : NULL,
3311 (IMFStreamSink *)event_source);
3312 LeaveCriticalSection(&session->cs);
3314 break;
3315 case MEQualityNotify:
3317 if (session->quality_manager)
3319 if (FAILED(IMFMediaEventGenerator_QueryInterface(event_source, &IID_IMFStreamSink, (void **)&object)))
3320 IMFMediaEventGenerator_QueryInterface(event_source, &IID_IMFTransform, (void **)&object);
3322 if (object)
3324 IMFQualityManager_NotifyQualityEvent(session->quality_manager, object, event);
3325 IUnknown_Release(object);
3329 break;
3330 default:
3334 PropVariantClear(&value);
3336 failed:
3337 if (event)
3338 IMFMediaEvent_Release(event);
3340 if (FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(event_source, iface, (IUnknown *)event_source)))
3341 WARN("Failed to re-subscribe, hr %#x.\n", hr);
3343 IMFMediaEventGenerator_Release(event_source);
3345 return hr;
3348 static const IMFAsyncCallbackVtbl session_events_callback_vtbl =
3350 session_events_callback_QueryInterface,
3351 session_events_callback_AddRef,
3352 session_events_callback_Release,
3353 session_events_callback_GetParameters,
3354 session_events_callback_Invoke,
3357 static HRESULT WINAPI session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
3359 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
3360 IsEqualIID(riid, &IID_IUnknown))
3362 *obj = iface;
3363 IMFAsyncCallback_AddRef(iface);
3364 return S_OK;
3367 WARN("Unsupported %s.\n", debugstr_guid(riid));
3368 *obj = NULL;
3369 return E_NOINTERFACE;
3372 static ULONG WINAPI session_sink_finalizer_callback_AddRef(IMFAsyncCallback *iface)
3374 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3375 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3378 static ULONG WINAPI session_sink_finalizer_callback_Release(IMFAsyncCallback *iface)
3380 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3381 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3384 static HRESULT WINAPI session_sink_finalizer_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
3386 return E_NOTIMPL;
3389 static HRESULT WINAPI session_sink_finalizer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
3391 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3392 IMFFinalizableMediaSink *fin_sink = NULL;
3393 BOOL sinks_finalized = TRUE;
3394 struct media_sink *sink;
3395 IUnknown *state;
3396 HRESULT hr;
3398 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
3399 return hr;
3401 EnterCriticalSection(&session->cs);
3403 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
3405 if (state == (IUnknown *)sink->sink)
3407 if (FAILED(hr = IMFMediaSink_QueryInterface(sink->sink, &IID_IMFFinalizableMediaSink, (void **)&fin_sink)))
3408 WARN("Unexpected, missing IMFFinalizableMediaSink, hr %#x.\n", hr);
3410 else
3412 sinks_finalized &= sink->finalized;
3413 if (!sinks_finalized)
3414 break;
3418 IUnknown_Release(state);
3420 if (fin_sink)
3422 /* Complete session transition, or close prematurely on error. */
3423 if (SUCCEEDED(hr = IMFFinalizableMediaSink_EndFinalize(fin_sink, result)))
3425 sink->finalized = TRUE;
3426 if (sinks_finalized)
3427 session_set_closed(session, hr);
3429 IMFFinalizableMediaSink_Release(fin_sink);
3432 LeaveCriticalSection(&session->cs);
3434 return S_OK;
3437 static const IMFAsyncCallbackVtbl session_sink_finalizer_callback_vtbl =
3439 session_sink_finalizer_callback_QueryInterface,
3440 session_sink_finalizer_callback_AddRef,
3441 session_sink_finalizer_callback_Release,
3442 session_sink_finalizer_callback_GetParameters,
3443 session_sink_finalizer_callback_Invoke,
3446 static HRESULT WINAPI session_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
3448 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3449 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
3452 static ULONG WINAPI session_rate_support_AddRef(IMFRateSupport *iface)
3454 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3455 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3458 static ULONG WINAPI session_rate_support_Release(IMFRateSupport *iface)
3460 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3461 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3464 static HRESULT session_presentation_object_get_rate(IUnknown *object, MFRATE_DIRECTION direction,
3465 BOOL thin, BOOL fastest, float *result)
3467 IMFRateSupport *rate_support;
3468 float rate;
3469 HRESULT hr;
3471 /* For objects that don't support rate control, it's assumed that only forward direction is allowed, at 1.0f. */
3473 if (FAILED(hr = MFGetService(object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support)))
3475 if (direction == MFRATE_FORWARD)
3477 *result = 1.0f;
3478 return S_OK;
3480 else
3481 return MF_E_REVERSE_UNSUPPORTED;
3484 rate = 0.0f;
3485 if (fastest)
3487 if (SUCCEEDED(hr = IMFRateSupport_GetFastestRate(rate_support, direction, thin, &rate)))
3488 *result = min(fabsf(rate), *result);
3490 else
3492 if (SUCCEEDED(hr = IMFRateSupport_GetSlowestRate(rate_support, direction, thin, &rate)))
3493 *result = max(fabsf(rate), *result);
3496 IMFRateSupport_Release(rate_support);
3498 return hr;
3501 static HRESULT session_get_presentation_rate(struct media_session *session, MFRATE_DIRECTION direction,
3502 BOOL thin, BOOL fastest, float *result)
3504 struct media_source *source;
3505 struct media_sink *sink;
3506 HRESULT hr = E_POINTER;
3507 float rate;
3509 rate = fastest ? FLT_MAX : 0.0f;
3511 EnterCriticalSection(&session->cs);
3513 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
3515 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3517 if (FAILED(hr = session_presentation_object_get_rate((IUnknown *)source->source, direction, thin, fastest, &rate)))
3518 break;
3521 if (SUCCEEDED(hr))
3523 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
3525 if (FAILED(hr = session_presentation_object_get_rate((IUnknown *)sink->sink, direction, thin, fastest, &rate)))
3526 break;
3531 LeaveCriticalSection(&session->cs);
3533 if (SUCCEEDED(hr))
3534 *result = direction == MFRATE_FORWARD ? rate : -rate;
3536 return hr;
3539 static HRESULT WINAPI session_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
3540 BOOL thin, float *rate)
3542 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3544 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
3546 return session_get_presentation_rate(session, direction, thin, FALSE, rate);
3549 static HRESULT WINAPI session_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
3550 BOOL thin, float *rate)
3552 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3554 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
3556 return session_get_presentation_rate(session, direction, thin, TRUE, rate);
3559 static HRESULT WINAPI session_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
3560 float *nearest_supported_rate)
3562 FIXME("%p, %d, %f, %p.\n", iface, thin, rate, nearest_supported_rate);
3564 return E_NOTIMPL;
3567 static const IMFRateSupportVtbl session_rate_support_vtbl =
3569 session_rate_support_QueryInterface,
3570 session_rate_support_AddRef,
3571 session_rate_support_Release,
3572 session_rate_support_GetSlowestRate,
3573 session_rate_support_GetFastestRate,
3574 session_rate_support_IsRateSupported,
3577 static HRESULT WINAPI session_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj)
3579 struct media_session *session = impl_session_from_IMFRateControl(iface);
3580 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
3583 static ULONG WINAPI session_rate_control_AddRef(IMFRateControl *iface)
3585 struct media_session *session = impl_session_from_IMFRateControl(iface);
3586 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3589 static ULONG WINAPI session_rate_control_Release(IMFRateControl *iface)
3591 struct media_session *session = impl_session_from_IMFRateControl(iface);
3592 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3595 static HRESULT WINAPI session_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate)
3597 FIXME("%p, %d, %f.\n", iface, thin, rate);
3599 return E_NOTIMPL;
3602 static HRESULT WINAPI session_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
3604 struct media_session *session = impl_session_from_IMFRateControl(iface);
3606 TRACE("%p, %p, %p.\n", iface, thin, rate);
3608 return IMFRateControl_GetRate(session->clock_rate_control, thin, rate);
3611 static const IMFRateControlVtbl session_rate_control_vtbl =
3613 session_rate_control_QueryInterface,
3614 session_rate_control_AddRef,
3615 session_rate_control_Release,
3616 session_rate_control_SetRate,
3617 session_rate_control_GetRate,
3620 static HRESULT WINAPI node_attribute_editor_QueryInterface(IMFTopologyNodeAttributeEditor *iface,
3621 REFIID riid, void **obj)
3623 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
3625 if (IsEqualIID(riid, &IID_IMFTopologyNodeAttributeEditor) ||
3626 IsEqualIID(riid, &IID_IUnknown))
3628 *obj = iface;
3629 IMFTopologyNodeAttributeEditor_AddRef(iface);
3630 return S_OK;
3633 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
3634 *obj = NULL;
3635 return E_NOINTERFACE;
3638 static ULONG WINAPI node_attribute_editor_AddRef(IMFTopologyNodeAttributeEditor *iface)
3640 struct media_session *session = impl_session_from_IMFTopologyNodeAttributeEditor(iface);
3641 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3644 static ULONG WINAPI node_attribute_editor_Release(IMFTopologyNodeAttributeEditor *iface)
3646 struct media_session *session = impl_session_from_IMFTopologyNodeAttributeEditor(iface);
3647 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3650 static HRESULT WINAPI node_attribute_editor_UpdateNodeAttributes(IMFTopologyNodeAttributeEditor *iface,
3651 TOPOID id, DWORD count, MFTOPONODE_ATTRIBUTE_UPDATE *updates)
3653 FIXME("%p, %s, %u, %p.\n", iface, wine_dbgstr_longlong(id), count, updates);
3655 return E_NOTIMPL;
3658 static const IMFTopologyNodeAttributeEditorVtbl node_attribute_editor_vtbl =
3660 node_attribute_editor_QueryInterface,
3661 node_attribute_editor_AddRef,
3662 node_attribute_editor_Release,
3663 node_attribute_editor_UpdateNodeAttributes,
3666 /***********************************************************************
3667 * MFCreateMediaSession (mf.@)
3669 HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **session)
3671 BOOL without_quality_manager = FALSE;
3672 struct media_session *object;
3673 HRESULT hr;
3675 TRACE("%p, %p.\n", config, session);
3677 if (!(object = calloc(1, sizeof(*object))))
3678 return E_OUTOFMEMORY;
3680 object->IMFMediaSession_iface.lpVtbl = &mfmediasessionvtbl;
3681 object->IMFGetService_iface.lpVtbl = &session_get_service_vtbl;
3682 object->IMFRateSupport_iface.lpVtbl = &session_rate_support_vtbl;
3683 object->IMFRateControl_iface.lpVtbl = &session_rate_control_vtbl;
3684 object->IMFTopologyNodeAttributeEditor_iface.lpVtbl = &node_attribute_editor_vtbl;
3685 object->commands_callback.lpVtbl = &session_commands_callback_vtbl;
3686 object->events_callback.lpVtbl = &session_events_callback_vtbl;
3687 object->sink_finalizer_callback.lpVtbl = &session_sink_finalizer_callback_vtbl;
3688 object->refcount = 1;
3689 list_init(&object->topologies);
3690 list_init(&object->commands);
3691 list_init(&object->presentation.sources);
3692 list_init(&object->presentation.sinks);
3693 list_init(&object->presentation.nodes);
3694 InitializeCriticalSection(&object->cs);
3696 if (FAILED(hr = MFCreateTopology(&object->presentation.current_topology)))
3697 goto failed;
3699 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
3700 goto failed;
3702 if (FAILED(hr = MFCreatePresentationClock(&object->clock)))
3703 goto failed;
3705 if (FAILED(hr = MFCreateSystemTimeSource(&object->system_time_source)))
3706 goto failed;
3708 if (FAILED(hr = IMFPresentationClock_QueryInterface(object->clock, &IID_IMFRateControl,
3709 (void **)&object->clock_rate_control)))
3711 goto failed;
3714 if (config)
3716 GUID clsid;
3718 if (SUCCEEDED(IMFAttributes_GetGUID(config, &MF_SESSION_TOPOLOADER, &clsid)))
3720 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTopoLoader,
3721 (void **)&object->topo_loader)))
3723 WARN("Failed to create custom topology loader, hr %#x.\n", hr);
3727 if (SUCCEEDED(IMFAttributes_GetGUID(config, &MF_SESSION_QUALITY_MANAGER, &clsid)))
3729 if (!(without_quality_manager = IsEqualGUID(&clsid, &GUID_NULL)))
3731 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFQualityManager,
3732 (void **)&object->quality_manager)))
3734 WARN("Failed to create custom quality manager, hr %#x.\n", hr);
3740 if (!object->topo_loader && FAILED(hr = MFCreateTopoLoader(&object->topo_loader)))
3741 goto failed;
3743 if (!object->quality_manager && !without_quality_manager &&
3744 FAILED(hr = MFCreateStandardQualityManager(&object->quality_manager)))
3746 goto failed;
3749 if (object->quality_manager && FAILED(hr = IMFQualityManager_NotifyPresentationClock(object->quality_manager,
3750 object->clock)))
3752 goto failed;
3755 *session = &object->IMFMediaSession_iface;
3757 return S_OK;
3759 failed:
3760 IMFMediaSession_Release(&object->IMFMediaSession_iface);
3761 return hr;
3764 static HRESULT WINAPI standard_quality_manager_QueryInterface(IMFQualityManager *iface, REFIID riid, void **out)
3766 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3768 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
3770 if (IsEqualIID(riid, &IID_IMFQualityManager) ||
3771 IsEqualIID(riid, &IID_IUnknown))
3773 *out = iface;
3775 else if (IsEqualIID(riid, &IID_IMFClockStateSink))
3777 *out = &manager->IMFClockStateSink_iface;
3779 else
3781 WARN("Unsupported %s.\n", debugstr_guid(riid));
3782 *out = NULL;
3783 return E_NOINTERFACE;
3786 IUnknown_AddRef((IUnknown *)*out);
3787 return S_OK;
3790 static ULONG WINAPI standard_quality_manager_AddRef(IMFQualityManager *iface)
3792 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3793 ULONG refcount = InterlockedIncrement(&manager->refcount);
3795 TRACE("%p, refcount %u.\n", iface, refcount);
3797 return refcount;
3800 static ULONG WINAPI standard_quality_manager_Release(IMFQualityManager *iface)
3802 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3803 ULONG refcount = InterlockedDecrement(&manager->refcount);
3805 TRACE("%p, refcount %u.\n", iface, refcount);
3807 if (!refcount)
3809 if (manager->clock)
3810 IMFPresentationClock_Release(manager->clock);
3811 if (manager->topology)
3812 IMFTopology_Release(manager->topology);
3813 DeleteCriticalSection(&manager->cs);
3814 free(manager);
3817 return refcount;
3820 static void standard_quality_manager_set_topology(struct quality_manager *manager, IMFTopology *topology)
3822 if (manager->topology)
3823 IMFTopology_Release(manager->topology);
3824 manager->topology = topology;
3825 if (manager->topology)
3826 IMFTopology_AddRef(manager->topology);
3829 static HRESULT WINAPI standard_quality_manager_NotifyTopology(IMFQualityManager *iface, IMFTopology *topology)
3831 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3832 HRESULT hr = S_OK;
3834 TRACE("%p, %p.\n", iface, topology);
3836 EnterCriticalSection(&manager->cs);
3837 if (manager->state == QUALITY_MANAGER_SHUT_DOWN)
3838 hr = MF_E_SHUTDOWN;
3839 else
3841 standard_quality_manager_set_topology(manager, topology);
3843 LeaveCriticalSection(&manager->cs);
3845 return hr;
3848 static void standard_quality_manager_release_clock(struct quality_manager *manager)
3850 if (manager->clock)
3852 IMFPresentationClock_RemoveClockStateSink(manager->clock, &manager->IMFClockStateSink_iface);
3853 IMFPresentationClock_Release(manager->clock);
3855 manager->clock = NULL;
3858 static HRESULT WINAPI standard_quality_manager_NotifyPresentationClock(IMFQualityManager *iface,
3859 IMFPresentationClock *clock)
3861 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3862 HRESULT hr = S_OK;
3864 TRACE("%p, %p.\n", iface, clock);
3866 EnterCriticalSection(&manager->cs);
3867 if (manager->state == QUALITY_MANAGER_SHUT_DOWN)
3868 hr = MF_E_SHUTDOWN;
3869 else if (!clock)
3870 hr = E_POINTER;
3871 else
3873 standard_quality_manager_release_clock(manager);
3874 manager->clock = clock;
3875 IMFPresentationClock_AddRef(manager->clock);
3876 if (FAILED(IMFPresentationClock_AddClockStateSink(manager->clock, &manager->IMFClockStateSink_iface)))
3877 WARN("Failed to set state sink.\n");
3879 LeaveCriticalSection(&manager->cs);
3881 return hr;
3884 static HRESULT WINAPI standard_quality_manager_NotifyProcessInput(IMFQualityManager *iface, IMFTopologyNode *node,
3885 LONG input_index, IMFSample *sample)
3887 TRACE("%p, %p, %d, %p stub.\n", iface, node, input_index, sample);
3889 return E_NOTIMPL;
3892 static HRESULT WINAPI standard_quality_manager_NotifyProcessOutput(IMFQualityManager *iface, IMFTopologyNode *node,
3893 LONG output_index, IMFSample *sample)
3895 TRACE("%p, %p, %d, %p stub.\n", iface, node, output_index, sample);
3897 return E_NOTIMPL;
3900 static HRESULT WINAPI standard_quality_manager_NotifyQualityEvent(IMFQualityManager *iface, IUnknown *object,
3901 IMFMediaEvent *event)
3903 FIXME("%p, %p, %p stub.\n", iface, object, event);
3905 return E_NOTIMPL;
3908 static HRESULT WINAPI standard_quality_manager_Shutdown(IMFQualityManager *iface)
3910 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3912 TRACE("%p.\n", iface);
3914 EnterCriticalSection(&manager->cs);
3915 if (manager->state != QUALITY_MANAGER_SHUT_DOWN)
3917 standard_quality_manager_release_clock(manager);
3918 standard_quality_manager_set_topology(manager, NULL);
3919 manager->state = QUALITY_MANAGER_SHUT_DOWN;
3921 LeaveCriticalSection(&manager->cs);
3923 return S_OK;
3926 static const IMFQualityManagerVtbl standard_quality_manager_vtbl =
3928 standard_quality_manager_QueryInterface,
3929 standard_quality_manager_AddRef,
3930 standard_quality_manager_Release,
3931 standard_quality_manager_NotifyTopology,
3932 standard_quality_manager_NotifyPresentationClock,
3933 standard_quality_manager_NotifyProcessInput,
3934 standard_quality_manager_NotifyProcessOutput,
3935 standard_quality_manager_NotifyQualityEvent,
3936 standard_quality_manager_Shutdown,
3939 static HRESULT WINAPI standard_quality_manager_sink_QueryInterface(IMFClockStateSink *iface,
3940 REFIID riid, void **obj)
3942 struct quality_manager *manager = impl_from_qm_IMFClockStateSink(iface);
3943 return IMFQualityManager_QueryInterface(&manager->IMFQualityManager_iface, riid, obj);
3946 static ULONG WINAPI standard_quality_manager_sink_AddRef(IMFClockStateSink *iface)
3948 struct quality_manager *manager = impl_from_qm_IMFClockStateSink(iface);
3949 return IMFQualityManager_AddRef(&manager->IMFQualityManager_iface);
3952 static ULONG WINAPI standard_quality_manager_sink_Release(IMFClockStateSink *iface)
3954 struct quality_manager *manager = impl_from_qm_IMFClockStateSink(iface);
3955 return IMFQualityManager_Release(&manager->IMFQualityManager_iface);
3958 static HRESULT WINAPI standard_quality_manager_sink_OnClockStart(IMFClockStateSink *iface,
3959 MFTIME systime, LONGLONG offset)
3961 return S_OK;
3964 static HRESULT WINAPI standard_quality_manager_sink_OnClockStop(IMFClockStateSink *iface,
3965 MFTIME systime)
3967 return S_OK;
3970 static HRESULT WINAPI standard_quality_manager_sink_OnClockPause(IMFClockStateSink *iface,
3971 MFTIME systime)
3973 return S_OK;
3976 static HRESULT WINAPI standard_quality_manager_sink_OnClockRestart(IMFClockStateSink *iface,
3977 MFTIME systime)
3979 return S_OK;
3982 static HRESULT WINAPI standard_quality_manager_sink_OnClockSetRate(IMFClockStateSink *iface,
3983 MFTIME systime, float rate)
3985 return S_OK;
3988 static const IMFClockStateSinkVtbl standard_quality_manager_sink_vtbl =
3990 standard_quality_manager_sink_QueryInterface,
3991 standard_quality_manager_sink_AddRef,
3992 standard_quality_manager_sink_Release,
3993 standard_quality_manager_sink_OnClockStart,
3994 standard_quality_manager_sink_OnClockStop,
3995 standard_quality_manager_sink_OnClockPause,
3996 standard_quality_manager_sink_OnClockRestart,
3997 standard_quality_manager_sink_OnClockSetRate,
4000 HRESULT WINAPI MFCreateStandardQualityManager(IMFQualityManager **manager)
4002 struct quality_manager *object;
4004 TRACE("%p.\n", manager);
4006 if (!(object = calloc(1, sizeof(*object))))
4007 return E_OUTOFMEMORY;
4009 object->IMFQualityManager_iface.lpVtbl = &standard_quality_manager_vtbl;
4010 object->IMFClockStateSink_iface.lpVtbl = &standard_quality_manager_sink_vtbl;
4011 object->refcount = 1;
4012 InitializeCriticalSection(&object->cs);
4014 *manager = &object->IMFQualityManager_iface;
4016 return S_OK;