d3d10/effect: Add a helper to read raw variable values.
[wine.git] / dlls / mf / session.c
blobe3d7786449479d0ac8ac937982d17590e2c440ec
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) ||
2084 IsEqualGUID(service, &MR_STREAM_VOLUME_SERVICE))
2086 hr = session_get_audio_render_service(session, service, riid, obj);
2088 else
2089 FIXME("Unsupported service %s.\n", debugstr_guid(service));
2091 LeaveCriticalSection(&session->cs);
2093 return hr;
2096 static const IMFGetServiceVtbl session_get_service_vtbl =
2098 session_get_service_QueryInterface,
2099 session_get_service_AddRef,
2100 session_get_service_Release,
2101 session_get_service_GetService,
2104 static HRESULT WINAPI session_commands_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
2106 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
2107 IsEqualIID(riid, &IID_IUnknown))
2109 *obj = iface;
2110 IMFAsyncCallback_AddRef(iface);
2111 return S_OK;
2114 WARN("Unsupported %s.\n", debugstr_guid(riid));
2115 *obj = NULL;
2116 return E_NOINTERFACE;
2119 static ULONG WINAPI session_commands_callback_AddRef(IMFAsyncCallback *iface)
2121 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2122 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2125 static ULONG WINAPI session_commands_callback_Release(IMFAsyncCallback *iface)
2127 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2128 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2131 static HRESULT WINAPI session_commands_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
2133 return E_NOTIMPL;
2136 static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
2138 struct session_op *op = impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result));
2139 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2140 struct topo_node *topo_node;
2141 IMFTopologyNode *upstream_node;
2142 unsigned int upstream_output;
2144 EnterCriticalSection(&session->cs);
2146 switch (op->command)
2148 case SESSION_CMD_CLEAR_TOPOLOGIES:
2149 session_clear_topologies(session);
2150 break;
2151 case SESSION_CMD_SET_TOPOLOGY:
2152 session_set_topology(session, op->u.set_topology.flags, op->u.set_topology.topology);
2153 session_command_complete(session);
2154 break;
2155 case SESSION_CMD_START:
2156 session_start(session, &op->u.start.time_format, &op->u.start.start_position);
2157 break;
2158 case SESSION_CMD_PAUSE:
2159 session_pause(session);
2160 break;
2161 case SESSION_CMD_STOP:
2162 session_stop(session);
2163 break;
2164 case SESSION_CMD_CLOSE:
2165 session_close(session);
2166 break;
2167 case SESSION_CMD_QM_NOTIFY_TOPOLOGY:
2168 IMFQualityManager_NotifyTopology(session->quality_manager, op->u.notify_topology.topology);
2169 session_command_complete(session);
2170 break;
2171 case SESSION_CMD_SA_READY:
2172 topo_node = session_get_node_by_id(session, op->u.sa_ready.node_id);
2174 if (topo_node->u.sink.requests)
2176 if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node->node, 0, &upstream_node, &upstream_output)))
2178 session_request_sample_from_node(session, upstream_node, upstream_output);
2179 IMFTopologyNode_Release(upstream_node);
2182 break;
2183 default:
2187 LeaveCriticalSection(&session->cs);
2189 return S_OK;
2192 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl =
2194 session_commands_callback_QueryInterface,
2195 session_commands_callback_AddRef,
2196 session_commands_callback_Release,
2197 session_commands_callback_GetParameters,
2198 session_commands_callback_Invoke,
2201 static HRESULT WINAPI session_events_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
2203 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
2204 IsEqualIID(riid, &IID_IUnknown))
2206 *obj = iface;
2207 IMFAsyncCallback_AddRef(iface);
2208 return S_OK;
2211 WARN("Unsupported %s.\n", debugstr_guid(riid));
2212 *obj = NULL;
2213 return E_NOINTERFACE;
2216 static ULONG WINAPI session_events_callback_AddRef(IMFAsyncCallback *iface)
2218 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
2219 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2222 static ULONG WINAPI session_events_callback_Release(IMFAsyncCallback *iface)
2224 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
2225 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2228 static HRESULT WINAPI session_events_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
2230 return E_NOTIMPL;
2233 static HRESULT session_add_media_stream(struct media_session *session, IMFMediaSource *source, IMFMediaStream *stream)
2235 struct topo_node *node;
2236 IMFStreamDescriptor *sd;
2237 DWORD stream_id = 0;
2238 HRESULT hr;
2240 if (FAILED(hr = IMFMediaStream_GetStreamDescriptor(stream, &sd)))
2241 return hr;
2243 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &stream_id);
2244 IMFStreamDescriptor_Release(sd);
2245 if (FAILED(hr))
2246 return hr;
2248 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2250 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->u.source.source == source
2251 && node->u.source.stream_id == stream_id)
2253 if (node->object.source_stream)
2255 WARN("Node already has stream set.\n");
2256 return S_FALSE;
2259 node->object.source_stream = stream;
2260 IMFMediaStream_AddRef(node->object.source_stream);
2261 break;
2265 return S_OK;
2268 static BOOL session_is_source_nodes_state(struct media_session *session, enum object_state state)
2270 struct media_source *source;
2271 struct topo_node *node;
2273 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2275 if (source->state != state)
2276 return FALSE;
2279 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2281 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->state != state)
2282 return FALSE;
2285 return TRUE;
2288 static BOOL session_is_output_nodes_state(struct media_session *session, enum object_state state)
2290 struct topo_node *node;
2292 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2294 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->state != state)
2295 return FALSE;
2298 return TRUE;
2301 static enum object_state session_get_object_state_for_event(MediaEventType event)
2303 switch (event)
2305 case MESourceStarted:
2306 case MEStreamStarted:
2307 case MEStreamSinkStarted:
2308 return OBJ_STATE_STARTED;
2309 case MESourcePaused:
2310 case MEStreamPaused:
2311 case MEStreamSinkPaused:
2312 return OBJ_STATE_PAUSED;
2313 case MESourceStopped:
2314 case MEStreamStopped:
2315 case MEStreamSinkStopped:
2316 return OBJ_STATE_STOPPED;
2317 case MEStreamSinkPrerolled:
2318 return OBJ_STATE_PREROLLED;
2319 default:
2320 return OBJ_STATE_INVALID;
2324 static void session_set_consumed_clock(IUnknown *object, IMFPresentationClock *clock)
2326 IMFClockConsumer *consumer;
2328 if (SUCCEEDED(IUnknown_QueryInterface(object, &IID_IMFClockConsumer, (void **)&consumer)))
2330 IMFClockConsumer_SetPresentationClock(consumer, clock);
2331 IMFClockConsumer_Release(consumer);
2335 static void session_set_presentation_clock(struct media_session *session)
2337 IMFPresentationTimeSource *time_source = NULL;
2338 struct media_source *source;
2339 struct media_sink *sink;
2340 struct topo_node *node;
2341 HRESULT hr;
2343 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2345 if (node->type == MF_TOPOLOGY_TRANSFORM_NODE)
2346 IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
2349 if (!(session->presentation.flags & SESSION_FLAG_PRESENTATION_CLOCK_SET))
2351 /* Attempt to get time source from the sinks. */
2352 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2354 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink->sink, &IID_IMFPresentationTimeSource,
2355 (void **)&time_source)))
2356 break;
2359 if (time_source)
2361 hr = IMFPresentationClock_SetTimeSource(session->clock, time_source);
2362 IMFPresentationTimeSource_Release(time_source);
2364 else
2365 hr = IMFPresentationClock_SetTimeSource(session->clock, session->system_time_source);
2367 if (FAILED(hr))
2368 WARN("Failed to set time source, hr %#x.\n", hr);
2370 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2372 if (node->type != MF_TOPOLOGY_OUTPUT_NODE)
2373 continue;
2375 if (FAILED(hr = IMFStreamSink_BeginGetEvent(node->object.sink_stream, &session->events_callback,
2376 node->object.object)))
2378 WARN("Failed to subscribe to stream sink events, hr %#x.\n", hr);
2382 /* Set clock for all topology nodes. */
2383 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2385 session_set_consumed_clock((IUnknown *)source->source, session->clock);
2388 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2390 if (sink->event_generator && FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(sink->event_generator,
2391 &session->events_callback, (IUnknown *)sink->event_generator)))
2393 WARN("Failed to subscribe to sink events, hr %#x.\n", hr);
2396 if (FAILED(hr = IMFMediaSink_SetPresentationClock(sink->sink, session->clock)))
2397 WARN("Failed to set presentation clock for the sink, hr %#x.\n", hr);
2400 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2402 if (node->type != MF_TOPOLOGY_TRANSFORM_NODE)
2403 continue;
2405 session_set_consumed_clock(node->object.object, session->clock);
2408 session->presentation.flags |= SESSION_FLAG_PRESENTATION_CLOCK_SET;
2412 static HRESULT session_start_clock(struct media_session *session)
2414 LONGLONG start_offset = 0;
2415 HRESULT hr;
2417 if (IsEqualGUID(&session->presentation.time_format, &GUID_NULL))
2419 if (session->presentation.start_position.vt == VT_EMPTY)
2420 start_offset = PRESENTATION_CURRENT_POSITION;
2421 else if (session->presentation.start_position.vt == VT_I8)
2422 start_offset = session->presentation.start_position.hVal.QuadPart;
2423 else
2424 FIXME("Unhandled position type %d.\n", session->presentation.start_position.vt);
2426 else
2427 FIXME("Unhandled time format %s.\n", debugstr_guid(&session->presentation.time_format));
2429 if (FAILED(hr = IMFPresentationClock_Start(session->clock, start_offset)))
2430 WARN("Failed to start session clock, hr %#x.\n", hr);
2432 return hr;
2435 static struct topo_node *session_get_node_object(struct media_session *session, IUnknown *object,
2436 MF_TOPOLOGY_TYPE node_type)
2438 struct topo_node *node = NULL;
2440 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2442 if (node->type == node_type && object == node->object.object)
2443 break;
2446 return node;
2449 static BOOL session_set_node_object_state(struct media_session *session, IUnknown *object,
2450 MF_TOPOLOGY_TYPE node_type, enum object_state state)
2452 struct topo_node *node;
2453 BOOL changed = FALSE;
2455 if ((node = session_get_node_object(session, object, node_type)))
2457 changed = node->state != state;
2458 node->state = state;
2461 return changed;
2464 static void session_set_source_object_state(struct media_session *session, IUnknown *object,
2465 MediaEventType event_type)
2467 IMFStreamSink *stream_sink;
2468 struct media_source *src;
2469 struct media_sink *sink;
2470 enum object_state state;
2471 struct topo_node *node;
2472 unsigned int i, count;
2473 BOOL changed = FALSE;
2474 HRESULT hr;
2476 if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
2477 return;
2479 switch (event_type)
2481 case MESourceStarted:
2482 case MESourcePaused:
2483 case MESourceStopped:
2485 LIST_FOR_EACH_ENTRY(src, &session->presentation.sources, struct media_source, entry)
2487 if (object == (IUnknown *)src->source)
2489 changed = src->state != state;
2490 src->state = state;
2491 break;
2494 break;
2495 case MEStreamStarted:
2496 case MEStreamPaused:
2497 case MEStreamStopped:
2499 changed = session_set_node_object_state(session, object, MF_TOPOLOGY_SOURCESTREAM_NODE, state);
2500 default:
2504 if (!changed)
2505 return;
2507 switch (session->state)
2509 case SESSION_STATE_STARTING_SOURCES:
2510 if (!session_is_source_nodes_state(session, OBJ_STATE_STARTED))
2511 break;
2513 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_STARTED_SOURCE);
2515 session_set_presentation_clock(session);
2517 if (session->presentation.flags & SESSION_FLAG_NEEDS_PREROLL)
2519 MFTIME preroll_time = 0;
2521 if (session->presentation.start_position.vt == VT_I8)
2522 preroll_time = session->presentation.start_position.hVal.QuadPart;
2524 /* Mark stream sinks without prerolling support as PREROLLED to keep state test logic generic. */
2525 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2527 if (sink->preroll)
2529 /* FIXME: abort and enter error state on failure. */
2530 if (FAILED(hr = IMFMediaSinkPreroll_NotifyPreroll(sink->preroll, preroll_time)))
2531 WARN("Preroll notification failed, hr %#x.\n", hr);
2533 else
2535 if (SUCCEEDED(IMFMediaSink_GetStreamSinkCount(sink->sink, &count)))
2537 for (i = 0; i < count; ++i)
2539 if (SUCCEEDED(IMFMediaSink_GetStreamSinkByIndex(sink->sink, i, &stream_sink)))
2541 session_set_node_object_state(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE,
2542 OBJ_STATE_PREROLLED);
2543 IMFStreamSink_Release(stream_sink);
2549 session->state = SESSION_STATE_PREROLLING_SINKS;
2551 else if (SUCCEEDED(session_start_clock(session)))
2552 session->state = SESSION_STATE_STARTING_SINKS;
2554 break;
2555 case SESSION_STATE_PAUSING_SOURCES:
2556 if (!session_is_source_nodes_state(session, OBJ_STATE_PAUSED))
2557 break;
2559 session_set_paused(session, SESSION_STATE_PAUSED, S_OK);
2560 break;
2561 case SESSION_STATE_STOPPING_SOURCES:
2562 if (!session_is_source_nodes_state(session, OBJ_STATE_STOPPED))
2563 break;
2565 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2567 switch (node->type)
2569 case MF_TOPOLOGY_OUTPUT_NODE:
2570 IMFStreamSink_Flush(node->object.sink_stream);
2571 break;
2572 case MF_TOPOLOGY_TRANSFORM_NODE:
2573 IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_COMMAND_FLUSH, 0);
2574 break;
2575 default:
2580 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
2582 if (session->presentation.flags & SESSION_FLAG_FINALIZE_SINKS)
2583 session_finalize_sinks(session);
2584 else
2585 session_set_stopped(session, S_OK);
2587 break;
2588 default:
2593 static void session_set_sink_stream_state(struct media_session *session, IMFStreamSink *stream,
2594 MediaEventType event_type)
2596 struct media_source *source;
2597 enum object_state state;
2598 HRESULT hr = S_OK;
2599 BOOL changed;
2601 if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
2602 return;
2604 if (!(changed = session_set_node_object_state(session, (IUnknown *)stream, MF_TOPOLOGY_OUTPUT_NODE, state)))
2605 return;
2607 switch (session->state)
2609 case SESSION_STATE_PREROLLING_SINKS:
2610 if (!session_is_output_nodes_state(session, OBJ_STATE_PREROLLED))
2611 break;
2613 if (SUCCEEDED(session_start_clock(session)))
2614 session->state = SESSION_STATE_STARTING_SINKS;
2615 break;
2616 case SESSION_STATE_STARTING_SINKS:
2617 if (!session_is_output_nodes_state(session, OBJ_STATE_STARTED))
2618 break;
2620 session_set_started(session);
2621 break;
2622 case SESSION_STATE_PAUSING_SINKS:
2623 if (!session_is_output_nodes_state(session, OBJ_STATE_PAUSED))
2624 break;
2626 session->state = SESSION_STATE_PAUSING_SOURCES;
2628 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2630 if (FAILED(hr = IMFMediaSource_Pause(source->source)))
2631 break;
2634 if (FAILED(hr))
2635 session_set_paused(session, SESSION_STATE_PAUSED, hr);
2637 break;
2638 case SESSION_STATE_STOPPING_SINKS:
2639 if (!session_is_output_nodes_state(session, OBJ_STATE_STOPPED))
2640 break;
2642 session->state = SESSION_STATE_STOPPING_SOURCES;
2644 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2646 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION)
2647 IMFMediaSource_Stop(source->source);
2648 else if (FAILED(hr = IMFMediaSource_Stop(source->source)))
2649 break;
2652 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION || FAILED(hr))
2653 session_set_stopped(session, hr);
2655 break;
2656 default:
2661 static struct sample *transform_create_sample(IMFSample *sample)
2663 struct sample *sample_entry = calloc(1, sizeof(*sample_entry));
2665 if (sample_entry)
2667 sample_entry->sample = sample;
2668 if (sample_entry->sample)
2669 IMFSample_AddRef(sample_entry->sample);
2672 return sample_entry;
2675 static HRESULT transform_get_external_output_sample(const struct media_session *session, struct topo_node *transform,
2676 unsigned int output_index, const MFT_OUTPUT_STREAM_INFO *stream_info, IMFSample **sample)
2678 unsigned int buffer_size, downstream_input;
2679 IMFTopologyNode *downstream_node;
2680 IMFMediaBuffer *buffer = NULL;
2681 struct topo_node *topo_node;
2682 TOPOID node_id;
2683 HRESULT hr;
2685 if (FAILED(IMFTopologyNode_GetOutput(transform->node, output_index, &downstream_node, &downstream_input)))
2687 WARN("Failed to get connected node for output %u.\n", output_index);
2688 return MF_E_UNEXPECTED;
2691 IMFTopologyNode_GetTopoNodeID(downstream_node, &node_id);
2692 IMFTopologyNode_Release(downstream_node);
2694 topo_node = session_get_node_by_id(session, node_id);
2696 if (topo_node->type == MF_TOPOLOGY_OUTPUT_NODE && topo_node->u.sink.allocator)
2698 hr = IMFVideoSampleAllocator_AllocateSample(topo_node->u.sink.allocator, sample);
2700 else
2702 buffer_size = max(stream_info->cbSize, transform->u.transform.outputs[output_index].min_buffer_size);
2704 hr = MFCreateAlignedMemoryBuffer(buffer_size, stream_info->cbAlignment, &buffer);
2705 if (SUCCEEDED(hr))
2706 hr = MFCreateSample(sample);
2708 if (SUCCEEDED(hr))
2709 hr = IMFSample_AddBuffer(*sample, buffer);
2711 if (buffer)
2712 IMFMediaBuffer_Release(buffer);
2715 return hr;
2718 static HRESULT transform_node_pull_samples(const struct media_session *session, struct topo_node *node)
2720 MFT_OUTPUT_STREAM_INFO stream_info;
2721 MFT_OUTPUT_DATA_BUFFER *buffers;
2722 struct sample *queued_sample;
2723 DWORD status = 0;
2724 unsigned int i;
2725 HRESULT hr = E_UNEXPECTED;
2727 if (!(buffers = calloc(node->u.transform.output_count, sizeof(*buffers))))
2728 return E_OUTOFMEMORY;
2730 for (i = 0; i < node->u.transform.output_count; ++i)
2732 buffers[i].dwStreamID = transform_node_get_stream_id(node, TRUE, i);
2733 buffers[i].pSample = NULL;
2734 buffers[i].dwStatus = 0;
2735 buffers[i].pEvents = NULL;
2737 memset(&stream_info, 0, sizeof(stream_info));
2738 if (FAILED(hr = IMFTransform_GetOutputStreamInfo(node->object.transform, buffers[i].dwStreamID, &stream_info)))
2739 break;
2741 if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)))
2743 if (FAILED(hr = transform_get_external_output_sample(session, node, i, &stream_info, &buffers[i].pSample)))
2744 break;
2748 if (SUCCEEDED(hr))
2749 hr = IMFTransform_ProcessOutput(node->object.transform, 0, node->u.transform.output_count, buffers, &status);
2751 /* Collect returned samples for all streams. */
2752 for (i = 0; i < node->u.transform.output_count; ++i)
2754 if (buffers[i].pEvents)
2755 IMFCollection_Release(buffers[i].pEvents);
2757 if (SUCCEEDED(hr) && !(buffers[i].dwStatus & MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE))
2759 if (session->quality_manager)
2760 IMFQualityManager_NotifyProcessOutput(session->quality_manager, node->node, i, buffers[i].pSample);
2762 queued_sample = transform_create_sample(buffers[i].pSample);
2763 list_add_tail(&node->u.transform.outputs[i].samples, &queued_sample->entry);
2766 if (buffers[i].pSample)
2767 IMFSample_Release(buffers[i].pSample);
2770 free(buffers);
2772 return hr;
2775 static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input,
2776 IMFSample *sample)
2778 struct sample *sample_entry, *sample_entry2;
2779 DWORD stream_id, downstream_input;
2780 IMFTopologyNode *downstream_node;
2781 struct topo_node *topo_node;
2782 MF_TOPOLOGY_TYPE node_type;
2783 BOOL drain = FALSE;
2784 TOPOID node_id;
2785 unsigned int i;
2786 HRESULT hr;
2788 if (session->quality_manager)
2789 IMFQualityManager_NotifyProcessInput(session->quality_manager, node, input, sample);
2791 IMFTopologyNode_GetNodeType(node, &node_type);
2792 IMFTopologyNode_GetTopoNodeID(node, &node_id);
2794 topo_node = session_get_node_by_id(session, node_id);
2796 switch (node_type)
2798 case MF_TOPOLOGY_OUTPUT_NODE:
2799 if (sample)
2801 if (topo_node->u.sink.requests)
2803 if (FAILED(hr = IMFStreamSink_ProcessSample(topo_node->object.sink_stream, sample)))
2804 WARN("Stream sink failed to process sample, hr %#x.\n", hr);
2805 topo_node->u.sink.requests--;
2808 else if (FAILED(hr = IMFStreamSink_PlaceMarker(topo_node->object.sink_stream, MFSTREAMSINK_MARKER_ENDOFSEGMENT,
2809 NULL, NULL)))
2811 WARN("Failed to place sink marker, hr %#x.\n", hr);
2813 break;
2814 case MF_TOPOLOGY_TRANSFORM_NODE:
2816 transform_node_pull_samples(session, topo_node);
2818 sample_entry = transform_create_sample(sample);
2819 list_add_tail(&topo_node->u.transform.inputs[input].samples, &sample_entry->entry);
2821 for (i = 0; i < topo_node->u.transform.input_count; ++i)
2823 stream_id = transform_node_get_stream_id(topo_node, FALSE, i);
2824 LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.inputs[i].samples,
2825 struct sample, entry)
2827 if (sample_entry->sample)
2829 if ((hr = IMFTransform_ProcessInput(topo_node->object.transform, stream_id,
2830 sample_entry->sample, 0)) == MF_E_NOTACCEPTING)
2831 break;
2832 if (FAILED(hr))
2833 WARN("Failed to process input for stream %u/%u, hr %#x.\n", i, stream_id, hr);
2834 transform_release_sample(sample_entry);
2836 else
2838 transform_stream_drop_samples(&topo_node->u.transform.inputs[i]);
2839 drain = TRUE;
2844 if (drain)
2846 if (FAILED(hr = IMFTransform_ProcessMessage(topo_node->object.transform, MFT_MESSAGE_COMMAND_DRAIN, 0)))
2847 WARN("Drain command failed for transform, hr %#x.\n", hr);
2850 transform_node_pull_samples(session, topo_node);
2852 /* Remaining unprocessed input has been discarded, now queue markers for every output. */
2853 if (drain)
2855 for (i = 0; i < topo_node->u.transform.output_count; ++i)
2857 if ((sample_entry = transform_create_sample(NULL)))
2858 list_add_tail(&topo_node->u.transform.outputs[i].samples, &sample_entry->entry);
2862 /* Push down all available output. */
2863 for (i = 0; i < topo_node->u.transform.output_count; ++i)
2865 if (FAILED(IMFTopologyNode_GetOutput(node, i, &downstream_node, &downstream_input)))
2867 WARN("Failed to get connected node for output %u.\n", i);
2868 continue;
2871 LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.outputs[i].samples,
2872 struct sample, entry)
2874 if (!topo_node->u.transform.outputs[i].requests)
2875 break;
2877 session_deliver_sample_to_node(session, downstream_node, downstream_input, sample_entry->sample);
2878 topo_node->u.transform.outputs[i].requests--;
2880 transform_release_sample(sample_entry);
2883 IMFTopologyNode_Release(downstream_node);
2886 break;
2887 case MF_TOPOLOGY_TEE_NODE:
2888 FIXME("Unhandled downstream node type %d.\n", node_type);
2889 break;
2890 default:
2895 static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output)
2897 IMFTopologyNode *downstream_node, *upstream_node;
2898 unsigned int downstream_input, upstream_output;
2899 struct topo_node *topo_node;
2900 MF_TOPOLOGY_TYPE node_type;
2901 struct sample *sample;
2902 TOPOID node_id;
2903 HRESULT hr;
2905 IMFTopologyNode_GetNodeType(node, &node_type);
2906 IMFTopologyNode_GetTopoNodeID(node, &node_id);
2908 topo_node = session_get_node_by_id(session, node_id);
2910 switch (node_type)
2912 case MF_TOPOLOGY_SOURCESTREAM_NODE:
2913 if (FAILED(hr = IMFMediaStream_RequestSample(topo_node->object.source_stream, NULL)))
2914 WARN("Sample request failed, hr %#x.\n", hr);
2915 break;
2916 case MF_TOPOLOGY_TRANSFORM_NODE:
2918 if (list_empty(&topo_node->u.transform.outputs[output].samples))
2920 /* Forward request to upstream node. */
2921 if (SUCCEEDED(hr = IMFTopologyNode_GetInput(node, 0 /* FIXME */, &upstream_node, &upstream_output)))
2923 if (SUCCEEDED(hr = session_request_sample_from_node(session, upstream_node, upstream_output)))
2924 topo_node->u.transform.outputs[output].requests++;
2925 IMFTopologyNode_Release(upstream_node);
2928 else
2930 if (SUCCEEDED(hr = IMFTopologyNode_GetOutput(node, output, &downstream_node, &downstream_input)))
2932 sample = LIST_ENTRY(list_head(&topo_node->u.transform.outputs[output].samples), struct sample, entry);
2933 session_deliver_sample_to_node(session, downstream_node, downstream_input, sample->sample);
2934 transform_release_sample(sample);
2935 IMFTopologyNode_Release(downstream_node);
2939 break;
2940 case MF_TOPOLOGY_TEE_NODE:
2941 FIXME("Unhandled upstream node type %d.\n", node_type);
2942 default:
2943 hr = E_UNEXPECTED;
2946 return hr;
2949 static void session_request_sample(struct media_session *session, IMFStreamSink *sink_stream)
2951 struct topo_node *sink_node = NULL, *node;
2952 IMFTopologyNode *upstream_node;
2953 DWORD upstream_output;
2954 HRESULT hr;
2956 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2958 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink_stream)
2960 sink_node = node;
2961 break;
2965 if (!sink_node)
2966 return;
2968 if (FAILED(hr = IMFTopologyNode_GetInput(sink_node->node, 0, &upstream_node, &upstream_output)))
2970 WARN("Failed to get upstream node connection, hr %#x.\n", hr);
2971 return;
2974 if (SUCCEEDED(session_request_sample_from_node(session, upstream_node, upstream_output)))
2975 sink_node->u.sink.requests++;
2976 IMFTopologyNode_Release(upstream_node);
2979 static void session_deliver_sample(struct media_session *session, IMFMediaStream *stream, const PROPVARIANT *value)
2981 struct topo_node *source_node = NULL, *node;
2982 IMFTopologyNode *downstream_node;
2983 DWORD downstream_input;
2984 HRESULT hr;
2986 if (value && (value->vt != VT_UNKNOWN || !value->punkVal))
2988 WARN("Unexpected value type %d.\n", value->vt);
2989 return;
2992 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2994 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->object.source_stream == stream)
2996 source_node = node;
2997 break;
3001 if (!source_node)
3002 return;
3004 if (!value)
3005 source_node->flags |= TOPO_NODE_END_OF_STREAM;
3007 if (FAILED(hr = IMFTopologyNode_GetOutput(source_node->node, 0, &downstream_node, &downstream_input)))
3009 WARN("Failed to get downstream node connection, hr %#x.\n", hr);
3010 return;
3013 session_deliver_sample_to_node(session, downstream_node, downstream_input, value ? (IMFSample *)value->punkVal : NULL);
3014 IMFTopologyNode_Release(downstream_node);
3017 static void session_sink_invalidated(struct media_session *session, IMFMediaEvent *event, IMFStreamSink *sink)
3019 struct topo_node *node, *sink_node = NULL;
3020 HRESULT hr;
3022 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
3024 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink)
3026 sink_node = node;
3027 break;
3031 if (!sink_node)
3032 return;
3034 if (!event)
3036 if (FAILED(hr = MFCreateMediaEvent(MESinkInvalidated, &GUID_NULL, S_OK, NULL, &event)))
3037 WARN("Failed to create event, hr %#x.\n", hr);
3040 if (!event)
3041 return;
3043 IMFMediaEvent_SetUINT64(event, &MF_EVENT_OUTPUT_NODE, sink_node->node_id);
3044 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3046 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED);
3049 static BOOL session_nodes_is_mask_set(struct media_session *session, MF_TOPOLOGY_TYPE node_type, unsigned int flags)
3051 struct media_source *source;
3052 struct topo_node *node;
3054 if (node_type == MF_TOPOLOGY_MAX)
3056 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3058 if ((source->flags & flags) != flags)
3059 return FALSE;
3062 else
3064 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
3066 if (node->type == node_type && (node->flags & flags) != flags)
3067 return FALSE;
3071 return TRUE;
3074 static void session_raise_end_of_presentation(struct media_session *session)
3076 if (!(session_nodes_is_mask_set(session, MF_TOPOLOGY_SOURCESTREAM_NODE, TOPO_NODE_END_OF_STREAM)))
3077 return;
3079 if (!(session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION))
3081 if (session_nodes_is_mask_set(session, MF_TOPOLOGY_MAX, SOURCE_FLAG_END_OF_PRESENTATION))
3083 session->presentation.flags |= SESSION_FLAG_END_OF_PRESENTATION;
3084 session_push_back_command(session, SESSION_CMD_END);
3085 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, NULL);
3090 static void session_handle_end_of_stream(struct media_session *session, IMFMediaStream *stream)
3092 struct topo_node *node;
3094 if (!(node = session_get_node_object(session, (IUnknown *)stream, MF_TOPOLOGY_SOURCESTREAM_NODE))
3095 || node->flags & TOPO_NODE_END_OF_STREAM)
3097 return;
3100 session_deliver_sample(session, stream, NULL);
3102 session_raise_end_of_presentation(session);
3105 static void session_handle_end_of_presentation(struct media_session *session, IMFMediaSource *object)
3107 struct media_source *source;
3109 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3111 if (source->source == object)
3113 if (!(source->flags & SOURCE_FLAG_END_OF_PRESENTATION))
3115 source->flags |= SOURCE_FLAG_END_OF_PRESENTATION;
3116 session_raise_end_of_presentation(session);
3119 break;
3124 static void session_sink_stream_marker(struct media_session *session, IMFStreamSink *stream_sink)
3126 struct topo_node *node;
3128 if (!(node = session_get_node_object(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE))
3129 || node->flags & TOPO_NODE_END_OF_STREAM)
3131 return;
3134 node->flags |= TOPO_NODE_END_OF_STREAM;
3136 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION &&
3137 session_nodes_is_mask_set(session, MF_TOPOLOGY_OUTPUT_NODE, TOPO_NODE_END_OF_STREAM))
3139 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED);
3140 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
3141 session_stop(session);
3145 static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
3147 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
3148 IMFMediaEventGenerator *event_source;
3149 IMFMediaEvent *event = NULL;
3150 MediaEventType event_type;
3151 IUnknown *object = NULL;
3152 IMFMediaSource *source;
3153 IMFMediaStream *stream;
3154 PROPVARIANT value;
3155 HRESULT hr;
3157 if (FAILED(hr = IMFAsyncResult_GetState(result, (IUnknown **)&event_source)))
3158 return hr;
3160 if (FAILED(hr = IMFMediaEventGenerator_EndGetEvent(event_source, result, &event)))
3162 WARN("Failed to get event from %p, hr %#x.\n", event_source, hr);
3163 goto failed;
3166 if (FAILED(hr = IMFMediaEvent_GetType(event, &event_type)))
3168 WARN("Failed to get event type, hr %#x.\n", hr);
3169 goto failed;
3172 value.vt = VT_EMPTY;
3173 if (FAILED(hr = IMFMediaEvent_GetValue(event, &value)))
3175 WARN("Failed to get event value, hr %#x.\n", hr);
3176 goto failed;
3179 switch (event_type)
3181 case MESourceStarted:
3182 case MESourcePaused:
3183 case MESourceStopped:
3184 case MEStreamStarted:
3185 case MEStreamPaused:
3186 case MEStreamStopped:
3188 EnterCriticalSection(&session->cs);
3189 session_set_source_object_state(session, (IUnknown *)event_source, event_type);
3190 LeaveCriticalSection(&session->cs);
3192 break;
3194 case MEBufferingStarted:
3195 case MEBufferingStopped:
3197 EnterCriticalSection(&session->cs);
3198 if (session_get_media_source(session, (IMFMediaSource *)event_source))
3200 if (event_type == MEBufferingStarted)
3201 IMFPresentationClock_Pause(session->clock);
3202 else
3203 IMFPresentationClock_Start(session->clock, PRESENTATION_CURRENT_POSITION);
3205 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3207 LeaveCriticalSection(&session->cs);
3208 break;
3210 case MEReconnectStart:
3211 case MEReconnectEnd:
3213 EnterCriticalSection(&session->cs);
3214 if (session_get_media_source(session, (IMFMediaSource *)event_source))
3215 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3216 LeaveCriticalSection(&session->cs);
3217 break;
3219 case MEExtendedType:
3220 case MERendererEvent:
3221 case MEStreamSinkFormatChanged:
3223 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3224 break;
3226 case MENewStream:
3227 stream = (IMFMediaStream *)value.punkVal;
3229 if (value.vt != VT_UNKNOWN || !stream)
3231 WARN("Unexpected event value.\n");
3232 break;
3235 if (FAILED(hr = IMFMediaStream_GetMediaSource(stream, &source)))
3236 break;
3238 EnterCriticalSection(&session->cs);
3239 if (SUCCEEDED(hr = session_add_media_stream(session, source, stream)))
3240 hr = IMFMediaStream_BeginGetEvent(stream, &session->events_callback, (IUnknown *)stream);
3241 LeaveCriticalSection(&session->cs);
3243 IMFMediaSource_Release(source);
3245 break;
3246 case MEStreamSinkStarted:
3247 case MEStreamSinkPaused:
3248 case MEStreamSinkStopped:
3249 case MEStreamSinkPrerolled:
3251 EnterCriticalSection(&session->cs);
3252 session_set_sink_stream_state(session, (IMFStreamSink *)event_source, event_type);
3253 LeaveCriticalSection(&session->cs);
3255 break;
3256 case MEStreamSinkMarker:
3258 EnterCriticalSection(&session->cs);
3259 session_sink_stream_marker(session, (IMFStreamSink *)event_source);
3260 LeaveCriticalSection(&session->cs);
3262 break;
3263 case MEStreamSinkRequestSample:
3265 EnterCriticalSection(&session->cs);
3266 session_request_sample(session, (IMFStreamSink *)event_source);
3267 LeaveCriticalSection(&session->cs);
3269 break;
3270 case MEMediaSample:
3272 EnterCriticalSection(&session->cs);
3273 session_deliver_sample(session, (IMFMediaStream *)event_source, &value);
3274 LeaveCriticalSection(&session->cs);
3276 break;
3277 case MEEndOfStream:
3279 EnterCriticalSection(&session->cs);
3280 session_handle_end_of_stream(session, (IMFMediaStream *)event_source);
3281 LeaveCriticalSection(&session->cs);
3283 break;
3285 case MEEndOfPresentation:
3287 EnterCriticalSection(&session->cs);
3288 session_handle_end_of_presentation(session, (IMFMediaSource *)event_source);
3289 LeaveCriticalSection(&session->cs);
3291 break;
3292 case MEAudioSessionGroupingParamChanged:
3293 case MEAudioSessionIconChanged:
3294 case MEAudioSessionNameChanged:
3295 case MEAudioSessionVolumeChanged:
3297 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3299 break;
3300 case MEAudioSessionDeviceRemoved:
3301 case MEAudioSessionDisconnected:
3302 case MEAudioSessionExclusiveModeOverride:
3303 case MEAudioSessionFormatChanged:
3304 case MEAudioSessionServerShutdown:
3306 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3307 /* fallthrough */
3308 case MESinkInvalidated:
3310 EnterCriticalSection(&session->cs);
3311 session_sink_invalidated(session, event_type == MESinkInvalidated ? event : NULL,
3312 (IMFStreamSink *)event_source);
3313 LeaveCriticalSection(&session->cs);
3315 break;
3316 case MEQualityNotify:
3318 if (session->quality_manager)
3320 if (FAILED(IMFMediaEventGenerator_QueryInterface(event_source, &IID_IMFStreamSink, (void **)&object)))
3321 IMFMediaEventGenerator_QueryInterface(event_source, &IID_IMFTransform, (void **)&object);
3323 if (object)
3325 IMFQualityManager_NotifyQualityEvent(session->quality_manager, object, event);
3326 IUnknown_Release(object);
3330 break;
3331 default:
3335 PropVariantClear(&value);
3337 failed:
3338 if (event)
3339 IMFMediaEvent_Release(event);
3341 if (FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(event_source, iface, (IUnknown *)event_source)))
3342 WARN("Failed to re-subscribe, hr %#x.\n", hr);
3344 IMFMediaEventGenerator_Release(event_source);
3346 return hr;
3349 static const IMFAsyncCallbackVtbl session_events_callback_vtbl =
3351 session_events_callback_QueryInterface,
3352 session_events_callback_AddRef,
3353 session_events_callback_Release,
3354 session_events_callback_GetParameters,
3355 session_events_callback_Invoke,
3358 static HRESULT WINAPI session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
3360 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
3361 IsEqualIID(riid, &IID_IUnknown))
3363 *obj = iface;
3364 IMFAsyncCallback_AddRef(iface);
3365 return S_OK;
3368 WARN("Unsupported %s.\n", debugstr_guid(riid));
3369 *obj = NULL;
3370 return E_NOINTERFACE;
3373 static ULONG WINAPI session_sink_finalizer_callback_AddRef(IMFAsyncCallback *iface)
3375 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3376 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3379 static ULONG WINAPI session_sink_finalizer_callback_Release(IMFAsyncCallback *iface)
3381 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3382 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3385 static HRESULT WINAPI session_sink_finalizer_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
3387 return E_NOTIMPL;
3390 static HRESULT WINAPI session_sink_finalizer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
3392 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3393 IMFFinalizableMediaSink *fin_sink = NULL;
3394 BOOL sinks_finalized = TRUE;
3395 struct media_sink *sink;
3396 IUnknown *state;
3397 HRESULT hr;
3399 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
3400 return hr;
3402 EnterCriticalSection(&session->cs);
3404 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
3406 if (state == (IUnknown *)sink->sink)
3408 if (FAILED(hr = IMFMediaSink_QueryInterface(sink->sink, &IID_IMFFinalizableMediaSink, (void **)&fin_sink)))
3409 WARN("Unexpected, missing IMFFinalizableMediaSink, hr %#x.\n", hr);
3411 else
3413 sinks_finalized &= sink->finalized;
3414 if (!sinks_finalized)
3415 break;
3419 IUnknown_Release(state);
3421 if (fin_sink)
3423 /* Complete session transition, or close prematurely on error. */
3424 if (SUCCEEDED(hr = IMFFinalizableMediaSink_EndFinalize(fin_sink, result)))
3426 sink->finalized = TRUE;
3427 if (sinks_finalized)
3428 session_set_closed(session, hr);
3430 IMFFinalizableMediaSink_Release(fin_sink);
3433 LeaveCriticalSection(&session->cs);
3435 return S_OK;
3438 static const IMFAsyncCallbackVtbl session_sink_finalizer_callback_vtbl =
3440 session_sink_finalizer_callback_QueryInterface,
3441 session_sink_finalizer_callback_AddRef,
3442 session_sink_finalizer_callback_Release,
3443 session_sink_finalizer_callback_GetParameters,
3444 session_sink_finalizer_callback_Invoke,
3447 static HRESULT WINAPI session_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
3449 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3450 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
3453 static ULONG WINAPI session_rate_support_AddRef(IMFRateSupport *iface)
3455 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3456 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3459 static ULONG WINAPI session_rate_support_Release(IMFRateSupport *iface)
3461 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3462 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3465 static HRESULT session_presentation_object_get_rate(IUnknown *object, MFRATE_DIRECTION direction,
3466 BOOL thin, BOOL fastest, float *result)
3468 IMFRateSupport *rate_support;
3469 float rate;
3470 HRESULT hr;
3472 /* For objects that don't support rate control, it's assumed that only forward direction is allowed, at 1.0f. */
3474 if (FAILED(hr = MFGetService(object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support)))
3476 if (direction == MFRATE_FORWARD)
3478 *result = 1.0f;
3479 return S_OK;
3481 else
3482 return MF_E_REVERSE_UNSUPPORTED;
3485 rate = 0.0f;
3486 if (fastest)
3488 if (SUCCEEDED(hr = IMFRateSupport_GetFastestRate(rate_support, direction, thin, &rate)))
3489 *result = min(fabsf(rate), *result);
3491 else
3493 if (SUCCEEDED(hr = IMFRateSupport_GetSlowestRate(rate_support, direction, thin, &rate)))
3494 *result = max(fabsf(rate), *result);
3497 IMFRateSupport_Release(rate_support);
3499 return hr;
3502 static HRESULT session_get_presentation_rate(struct media_session *session, MFRATE_DIRECTION direction,
3503 BOOL thin, BOOL fastest, float *result)
3505 struct media_source *source;
3506 struct media_sink *sink;
3507 HRESULT hr = E_POINTER;
3508 float rate;
3510 rate = fastest ? FLT_MAX : 0.0f;
3512 EnterCriticalSection(&session->cs);
3514 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
3516 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3518 if (FAILED(hr = session_presentation_object_get_rate((IUnknown *)source->source, direction, thin, fastest, &rate)))
3519 break;
3522 if (SUCCEEDED(hr))
3524 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
3526 if (FAILED(hr = session_presentation_object_get_rate((IUnknown *)sink->sink, direction, thin, fastest, &rate)))
3527 break;
3532 LeaveCriticalSection(&session->cs);
3534 if (SUCCEEDED(hr))
3535 *result = direction == MFRATE_FORWARD ? rate : -rate;
3537 return hr;
3540 static HRESULT WINAPI session_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
3541 BOOL thin, float *rate)
3543 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3545 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
3547 return session_get_presentation_rate(session, direction, thin, FALSE, rate);
3550 static HRESULT WINAPI session_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
3551 BOOL thin, float *rate)
3553 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3555 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
3557 return session_get_presentation_rate(session, direction, thin, TRUE, rate);
3560 static HRESULT WINAPI session_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
3561 float *nearest_supported_rate)
3563 FIXME("%p, %d, %f, %p.\n", iface, thin, rate, nearest_supported_rate);
3565 return E_NOTIMPL;
3568 static const IMFRateSupportVtbl session_rate_support_vtbl =
3570 session_rate_support_QueryInterface,
3571 session_rate_support_AddRef,
3572 session_rate_support_Release,
3573 session_rate_support_GetSlowestRate,
3574 session_rate_support_GetFastestRate,
3575 session_rate_support_IsRateSupported,
3578 static HRESULT WINAPI session_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj)
3580 struct media_session *session = impl_session_from_IMFRateControl(iface);
3581 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
3584 static ULONG WINAPI session_rate_control_AddRef(IMFRateControl *iface)
3586 struct media_session *session = impl_session_from_IMFRateControl(iface);
3587 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3590 static ULONG WINAPI session_rate_control_Release(IMFRateControl *iface)
3592 struct media_session *session = impl_session_from_IMFRateControl(iface);
3593 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3596 static HRESULT WINAPI session_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate)
3598 FIXME("%p, %d, %f.\n", iface, thin, rate);
3600 return E_NOTIMPL;
3603 static HRESULT WINAPI session_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
3605 struct media_session *session = impl_session_from_IMFRateControl(iface);
3607 TRACE("%p, %p, %p.\n", iface, thin, rate);
3609 return IMFRateControl_GetRate(session->clock_rate_control, thin, rate);
3612 static const IMFRateControlVtbl session_rate_control_vtbl =
3614 session_rate_control_QueryInterface,
3615 session_rate_control_AddRef,
3616 session_rate_control_Release,
3617 session_rate_control_SetRate,
3618 session_rate_control_GetRate,
3621 static HRESULT WINAPI node_attribute_editor_QueryInterface(IMFTopologyNodeAttributeEditor *iface,
3622 REFIID riid, void **obj)
3624 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
3626 if (IsEqualIID(riid, &IID_IMFTopologyNodeAttributeEditor) ||
3627 IsEqualIID(riid, &IID_IUnknown))
3629 *obj = iface;
3630 IMFTopologyNodeAttributeEditor_AddRef(iface);
3631 return S_OK;
3634 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
3635 *obj = NULL;
3636 return E_NOINTERFACE;
3639 static ULONG WINAPI node_attribute_editor_AddRef(IMFTopologyNodeAttributeEditor *iface)
3641 struct media_session *session = impl_session_from_IMFTopologyNodeAttributeEditor(iface);
3642 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3645 static ULONG WINAPI node_attribute_editor_Release(IMFTopologyNodeAttributeEditor *iface)
3647 struct media_session *session = impl_session_from_IMFTopologyNodeAttributeEditor(iface);
3648 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3651 static HRESULT WINAPI node_attribute_editor_UpdateNodeAttributes(IMFTopologyNodeAttributeEditor *iface,
3652 TOPOID id, DWORD count, MFTOPONODE_ATTRIBUTE_UPDATE *updates)
3654 FIXME("%p, %s, %u, %p.\n", iface, wine_dbgstr_longlong(id), count, updates);
3656 return E_NOTIMPL;
3659 static const IMFTopologyNodeAttributeEditorVtbl node_attribute_editor_vtbl =
3661 node_attribute_editor_QueryInterface,
3662 node_attribute_editor_AddRef,
3663 node_attribute_editor_Release,
3664 node_attribute_editor_UpdateNodeAttributes,
3667 /***********************************************************************
3668 * MFCreateMediaSession (mf.@)
3670 HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **session)
3672 BOOL without_quality_manager = FALSE;
3673 struct media_session *object;
3674 HRESULT hr;
3676 TRACE("%p, %p.\n", config, session);
3678 if (!(object = calloc(1, sizeof(*object))))
3679 return E_OUTOFMEMORY;
3681 object->IMFMediaSession_iface.lpVtbl = &mfmediasessionvtbl;
3682 object->IMFGetService_iface.lpVtbl = &session_get_service_vtbl;
3683 object->IMFRateSupport_iface.lpVtbl = &session_rate_support_vtbl;
3684 object->IMFRateControl_iface.lpVtbl = &session_rate_control_vtbl;
3685 object->IMFTopologyNodeAttributeEditor_iface.lpVtbl = &node_attribute_editor_vtbl;
3686 object->commands_callback.lpVtbl = &session_commands_callback_vtbl;
3687 object->events_callback.lpVtbl = &session_events_callback_vtbl;
3688 object->sink_finalizer_callback.lpVtbl = &session_sink_finalizer_callback_vtbl;
3689 object->refcount = 1;
3690 list_init(&object->topologies);
3691 list_init(&object->commands);
3692 list_init(&object->presentation.sources);
3693 list_init(&object->presentation.sinks);
3694 list_init(&object->presentation.nodes);
3695 InitializeCriticalSection(&object->cs);
3697 if (FAILED(hr = MFCreateTopology(&object->presentation.current_topology)))
3698 goto failed;
3700 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
3701 goto failed;
3703 if (FAILED(hr = MFCreatePresentationClock(&object->clock)))
3704 goto failed;
3706 if (FAILED(hr = MFCreateSystemTimeSource(&object->system_time_source)))
3707 goto failed;
3709 if (FAILED(hr = IMFPresentationClock_QueryInterface(object->clock, &IID_IMFRateControl,
3710 (void **)&object->clock_rate_control)))
3712 goto failed;
3715 if (config)
3717 GUID clsid;
3719 if (SUCCEEDED(IMFAttributes_GetGUID(config, &MF_SESSION_TOPOLOADER, &clsid)))
3721 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTopoLoader,
3722 (void **)&object->topo_loader)))
3724 WARN("Failed to create custom topology loader, hr %#x.\n", hr);
3728 if (SUCCEEDED(IMFAttributes_GetGUID(config, &MF_SESSION_QUALITY_MANAGER, &clsid)))
3730 if (!(without_quality_manager = IsEqualGUID(&clsid, &GUID_NULL)))
3732 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFQualityManager,
3733 (void **)&object->quality_manager)))
3735 WARN("Failed to create custom quality manager, hr %#x.\n", hr);
3741 if (!object->topo_loader && FAILED(hr = MFCreateTopoLoader(&object->topo_loader)))
3742 goto failed;
3744 if (!object->quality_manager && !without_quality_manager &&
3745 FAILED(hr = MFCreateStandardQualityManager(&object->quality_manager)))
3747 goto failed;
3750 if (object->quality_manager && FAILED(hr = IMFQualityManager_NotifyPresentationClock(object->quality_manager,
3751 object->clock)))
3753 goto failed;
3756 *session = &object->IMFMediaSession_iface;
3758 return S_OK;
3760 failed:
3761 IMFMediaSession_Release(&object->IMFMediaSession_iface);
3762 return hr;
3765 static HRESULT WINAPI standard_quality_manager_QueryInterface(IMFQualityManager *iface, REFIID riid, void **out)
3767 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3769 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
3771 if (IsEqualIID(riid, &IID_IMFQualityManager) ||
3772 IsEqualIID(riid, &IID_IUnknown))
3774 *out = iface;
3776 else if (IsEqualIID(riid, &IID_IMFClockStateSink))
3778 *out = &manager->IMFClockStateSink_iface;
3780 else
3782 WARN("Unsupported %s.\n", debugstr_guid(riid));
3783 *out = NULL;
3784 return E_NOINTERFACE;
3787 IUnknown_AddRef((IUnknown *)*out);
3788 return S_OK;
3791 static ULONG WINAPI standard_quality_manager_AddRef(IMFQualityManager *iface)
3793 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3794 ULONG refcount = InterlockedIncrement(&manager->refcount);
3796 TRACE("%p, refcount %u.\n", iface, refcount);
3798 return refcount;
3801 static ULONG WINAPI standard_quality_manager_Release(IMFQualityManager *iface)
3803 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3804 ULONG refcount = InterlockedDecrement(&manager->refcount);
3806 TRACE("%p, refcount %u.\n", iface, refcount);
3808 if (!refcount)
3810 if (manager->clock)
3811 IMFPresentationClock_Release(manager->clock);
3812 if (manager->topology)
3813 IMFTopology_Release(manager->topology);
3814 DeleteCriticalSection(&manager->cs);
3815 free(manager);
3818 return refcount;
3821 static void standard_quality_manager_set_topology(struct quality_manager *manager, IMFTopology *topology)
3823 if (manager->topology)
3824 IMFTopology_Release(manager->topology);
3825 manager->topology = topology;
3826 if (manager->topology)
3827 IMFTopology_AddRef(manager->topology);
3830 static HRESULT WINAPI standard_quality_manager_NotifyTopology(IMFQualityManager *iface, IMFTopology *topology)
3832 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3833 HRESULT hr = S_OK;
3835 TRACE("%p, %p.\n", iface, topology);
3837 EnterCriticalSection(&manager->cs);
3838 if (manager->state == QUALITY_MANAGER_SHUT_DOWN)
3839 hr = MF_E_SHUTDOWN;
3840 else
3842 standard_quality_manager_set_topology(manager, topology);
3844 LeaveCriticalSection(&manager->cs);
3846 return hr;
3849 static void standard_quality_manager_release_clock(struct quality_manager *manager)
3851 if (manager->clock)
3853 IMFPresentationClock_RemoveClockStateSink(manager->clock, &manager->IMFClockStateSink_iface);
3854 IMFPresentationClock_Release(manager->clock);
3856 manager->clock = NULL;
3859 static HRESULT WINAPI standard_quality_manager_NotifyPresentationClock(IMFQualityManager *iface,
3860 IMFPresentationClock *clock)
3862 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3863 HRESULT hr = S_OK;
3865 TRACE("%p, %p.\n", iface, clock);
3867 EnterCriticalSection(&manager->cs);
3868 if (manager->state == QUALITY_MANAGER_SHUT_DOWN)
3869 hr = MF_E_SHUTDOWN;
3870 else if (!clock)
3871 hr = E_POINTER;
3872 else
3874 standard_quality_manager_release_clock(manager);
3875 manager->clock = clock;
3876 IMFPresentationClock_AddRef(manager->clock);
3877 if (FAILED(IMFPresentationClock_AddClockStateSink(manager->clock, &manager->IMFClockStateSink_iface)))
3878 WARN("Failed to set state sink.\n");
3880 LeaveCriticalSection(&manager->cs);
3882 return hr;
3885 static HRESULT WINAPI standard_quality_manager_NotifyProcessInput(IMFQualityManager *iface, IMFTopologyNode *node,
3886 LONG input_index, IMFSample *sample)
3888 TRACE("%p, %p, %d, %p stub.\n", iface, node, input_index, sample);
3890 return E_NOTIMPL;
3893 static HRESULT WINAPI standard_quality_manager_NotifyProcessOutput(IMFQualityManager *iface, IMFTopologyNode *node,
3894 LONG output_index, IMFSample *sample)
3896 TRACE("%p, %p, %d, %p stub.\n", iface, node, output_index, sample);
3898 return E_NOTIMPL;
3901 static HRESULT WINAPI standard_quality_manager_NotifyQualityEvent(IMFQualityManager *iface, IUnknown *object,
3902 IMFMediaEvent *event)
3904 FIXME("%p, %p, %p stub.\n", iface, object, event);
3906 return E_NOTIMPL;
3909 static HRESULT WINAPI standard_quality_manager_Shutdown(IMFQualityManager *iface)
3911 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3913 TRACE("%p.\n", iface);
3915 EnterCriticalSection(&manager->cs);
3916 if (manager->state != QUALITY_MANAGER_SHUT_DOWN)
3918 standard_quality_manager_release_clock(manager);
3919 standard_quality_manager_set_topology(manager, NULL);
3920 manager->state = QUALITY_MANAGER_SHUT_DOWN;
3922 LeaveCriticalSection(&manager->cs);
3924 return S_OK;
3927 static const IMFQualityManagerVtbl standard_quality_manager_vtbl =
3929 standard_quality_manager_QueryInterface,
3930 standard_quality_manager_AddRef,
3931 standard_quality_manager_Release,
3932 standard_quality_manager_NotifyTopology,
3933 standard_quality_manager_NotifyPresentationClock,
3934 standard_quality_manager_NotifyProcessInput,
3935 standard_quality_manager_NotifyProcessOutput,
3936 standard_quality_manager_NotifyQualityEvent,
3937 standard_quality_manager_Shutdown,
3940 static HRESULT WINAPI standard_quality_manager_sink_QueryInterface(IMFClockStateSink *iface,
3941 REFIID riid, void **obj)
3943 struct quality_manager *manager = impl_from_qm_IMFClockStateSink(iface);
3944 return IMFQualityManager_QueryInterface(&manager->IMFQualityManager_iface, riid, obj);
3947 static ULONG WINAPI standard_quality_manager_sink_AddRef(IMFClockStateSink *iface)
3949 struct quality_manager *manager = impl_from_qm_IMFClockStateSink(iface);
3950 return IMFQualityManager_AddRef(&manager->IMFQualityManager_iface);
3953 static ULONG WINAPI standard_quality_manager_sink_Release(IMFClockStateSink *iface)
3955 struct quality_manager *manager = impl_from_qm_IMFClockStateSink(iface);
3956 return IMFQualityManager_Release(&manager->IMFQualityManager_iface);
3959 static HRESULT WINAPI standard_quality_manager_sink_OnClockStart(IMFClockStateSink *iface,
3960 MFTIME systime, LONGLONG offset)
3962 return S_OK;
3965 static HRESULT WINAPI standard_quality_manager_sink_OnClockStop(IMFClockStateSink *iface,
3966 MFTIME systime)
3968 return S_OK;
3971 static HRESULT WINAPI standard_quality_manager_sink_OnClockPause(IMFClockStateSink *iface,
3972 MFTIME systime)
3974 return S_OK;
3977 static HRESULT WINAPI standard_quality_manager_sink_OnClockRestart(IMFClockStateSink *iface,
3978 MFTIME systime)
3980 return S_OK;
3983 static HRESULT WINAPI standard_quality_manager_sink_OnClockSetRate(IMFClockStateSink *iface,
3984 MFTIME systime, float rate)
3986 return S_OK;
3989 static const IMFClockStateSinkVtbl standard_quality_manager_sink_vtbl =
3991 standard_quality_manager_sink_QueryInterface,
3992 standard_quality_manager_sink_AddRef,
3993 standard_quality_manager_sink_Release,
3994 standard_quality_manager_sink_OnClockStart,
3995 standard_quality_manager_sink_OnClockStop,
3996 standard_quality_manager_sink_OnClockPause,
3997 standard_quality_manager_sink_OnClockRestart,
3998 standard_quality_manager_sink_OnClockSetRate,
4001 HRESULT WINAPI MFCreateStandardQualityManager(IMFQualityManager **manager)
4003 struct quality_manager *object;
4005 TRACE("%p.\n", manager);
4007 if (!(object = calloc(1, sizeof(*object))))
4008 return E_OUTOFMEMORY;
4010 object->IMFQualityManager_iface.lpVtbl = &standard_quality_manager_vtbl;
4011 object->IMFClockStateSink_iface.lpVtbl = &standard_quality_manager_sink_vtbl;
4012 object->refcount = 1;
4013 InitializeCriticalSection(&object->cs);
4015 *manager = &object->IMFQualityManager_iface;
4017 return S_OK;