wined3d: Use wined3d_mask_from_size() in shader_glsl_gather4().
[wine.git] / dlls / mf / session.c
blobc8ec1b5c33f58744f936cff9ad1631006475d7ab
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 union
127 IMFMediaSource *source;
128 IUnknown *object;
130 IMFPresentationDescriptor *pd;
131 enum object_state state;
132 unsigned int flags;
135 struct media_sink
137 struct list entry;
138 union
140 IMFMediaSink *sink;
141 IUnknown *object;
143 IMFMediaSinkPreroll *preroll;
144 IMFMediaEventGenerator *event_generator;
145 BOOL finalized;
148 struct sample
150 struct list entry;
151 IMFSample *sample;
154 struct transform_stream
156 struct list samples;
157 unsigned int requests;
158 unsigned int min_buffer_size;
161 enum topo_node_flags
163 TOPO_NODE_END_OF_STREAM = 0x1,
166 struct topo_node
168 struct list entry;
169 struct media_session *session;
170 MF_TOPOLOGY_TYPE type;
171 TOPOID node_id;
172 IMFTopologyNode *node;
173 enum object_state state;
174 unsigned int flags;
175 union
177 IMFMediaStream *source_stream;
178 IMFStreamSink *sink_stream;
179 IMFTransform *transform;
180 IUnknown *object;
181 } object;
183 union
185 struct
187 IMFMediaSource *source;
188 unsigned int stream_id;
189 } source;
190 struct
192 unsigned int requests;
193 IMFVideoSampleAllocatorNotify notify_cb;
194 IMFVideoSampleAllocator *allocator;
195 IMFVideoSampleAllocatorCallback *allocator_cb;
196 } sink;
197 struct
199 struct transform_stream *inputs;
200 unsigned int *input_map;
201 unsigned int input_count;
203 struct transform_stream *outputs;
204 unsigned int *output_map;
205 unsigned int output_count;
206 } transform;
207 } u;
210 enum presentation_flags
212 SESSION_FLAG_SOURCES_SUBSCRIBED = 0x1,
213 SESSION_FLAG_PRESENTATION_CLOCK_SET = 0x2,
214 SESSION_FLAG_FINALIZE_SINKS = 0x4,
215 SESSION_FLAG_NEEDS_PREROLL = 0x8,
216 SESSION_FLAG_END_OF_PRESENTATION = 0x10,
219 struct media_session
221 IMFMediaSession IMFMediaSession_iface;
222 IMFGetService IMFGetService_iface;
223 IMFRateSupport IMFRateSupport_iface;
224 IMFRateControl IMFRateControl_iface;
225 IMFTopologyNodeAttributeEditor IMFTopologyNodeAttributeEditor_iface;
226 IMFAsyncCallback commands_callback;
227 IMFAsyncCallback events_callback;
228 IMFAsyncCallback sink_finalizer_callback;
229 LONG refcount;
230 IMFMediaEventQueue *event_queue;
231 IMFPresentationClock *clock;
232 IMFPresentationTimeSource *system_time_source;
233 IMFRateControl *clock_rate_control;
234 IMFTopoLoader *topo_loader;
235 IMFQualityManager *quality_manager;
236 struct
238 IMFTopology *current_topology;
239 MF_TOPOSTATUS topo_status;
240 MFTIME clock_stop_time;
241 unsigned int flags;
242 struct list sources;
243 struct list sinks;
244 struct list nodes;
246 /* Latest Start() arguments. */
247 GUID time_format;
248 PROPVARIANT start_position;
249 } presentation;
250 struct list topologies;
251 struct list commands;
252 enum session_state state;
253 DWORD caps;
254 CRITICAL_SECTION cs;
257 enum quality_manager_state
259 QUALITY_MANAGER_READY = 0,
260 QUALITY_MANAGER_SHUT_DOWN,
263 struct quality_manager
265 IMFQualityManager IMFQualityManager_iface;
266 IMFClockStateSink IMFClockStateSink_iface;
267 LONG refcount;
269 IMFTopology *topology;
270 IMFPresentationClock *clock;
271 unsigned int state;
272 CRITICAL_SECTION cs;
275 static inline struct media_session *impl_from_IMFMediaSession(IMFMediaSession *iface)
277 return CONTAINING_RECORD(iface, struct media_session, IMFMediaSession_iface);
280 static struct media_session *impl_from_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
282 return CONTAINING_RECORD(iface, struct media_session, commands_callback);
285 static struct media_session *impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
287 return CONTAINING_RECORD(iface, struct media_session, events_callback);
290 static struct media_session *impl_from_sink_finalizer_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
292 return CONTAINING_RECORD(iface, struct media_session, sink_finalizer_callback);
295 static struct media_session *impl_from_IMFGetService(IMFGetService *iface)
297 return CONTAINING_RECORD(iface, struct media_session, IMFGetService_iface);
300 static struct media_session *impl_session_from_IMFRateSupport(IMFRateSupport *iface)
302 return CONTAINING_RECORD(iface, struct media_session, IMFRateSupport_iface);
305 static struct media_session *impl_session_from_IMFRateControl(IMFRateControl *iface)
307 return CONTAINING_RECORD(iface, struct media_session, IMFRateControl_iface);
310 static struct media_session *impl_session_from_IMFTopologyNodeAttributeEditor(IMFTopologyNodeAttributeEditor *iface)
312 return CONTAINING_RECORD(iface, struct media_session, IMFTopologyNodeAttributeEditor_iface);
315 static struct session_op *impl_op_from_IUnknown(IUnknown *iface)
317 return CONTAINING_RECORD(iface, struct session_op, IUnknown_iface);
320 static struct quality_manager *impl_from_IMFQualityManager(IMFQualityManager *iface)
322 return CONTAINING_RECORD(iface, struct quality_manager, IMFQualityManager_iface);
325 static struct quality_manager *impl_from_qm_IMFClockStateSink(IMFClockStateSink *iface)
327 return CONTAINING_RECORD(iface, struct quality_manager, IMFClockStateSink_iface);
330 static struct topo_node *impl_node_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify *iface)
332 return CONTAINING_RECORD(iface, struct topo_node, u.sink.notify_cb);
335 /* IMFLocalMFTRegistration */
336 static HRESULT WINAPI local_mft_registration_QueryInterface(IMFLocalMFTRegistration *iface, REFIID riid, void **obj)
338 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
340 if (IsEqualIID(riid, &IID_IMFLocalMFTRegistration) ||
341 IsEqualIID(riid, &IID_IUnknown))
343 *obj = iface;
344 IMFLocalMFTRegistration_AddRef(iface);
345 return S_OK;
348 WARN("Unexpected %s.\n", debugstr_guid(riid));
349 *obj = NULL;
350 return E_NOINTERFACE;
353 static ULONG WINAPI local_mft_registration_AddRef(IMFLocalMFTRegistration *iface)
355 return 2;
358 static ULONG WINAPI local_mft_registration_Release(IMFLocalMFTRegistration *iface)
360 return 1;
363 static HRESULT WINAPI local_mft_registration_RegisterMFTs(IMFLocalMFTRegistration *iface, MFT_REGISTRATION_INFO *info,
364 DWORD count)
366 HRESULT hr = S_OK;
367 DWORD i;
369 TRACE("%p, %p, %u.\n", iface, info, count);
371 for (i = 0; i < count; ++i)
373 if (FAILED(hr = MFTRegisterLocalByCLSID(&info[i].clsid, &info[i].guidCategory, info[i].pszName,
374 info[i].uiFlags, info[i].cInTypes, info[i].pInTypes, info[i].cOutTypes, info[i].pOutTypes)))
376 break;
380 return hr;
383 static const IMFLocalMFTRegistrationVtbl local_mft_registration_vtbl =
385 local_mft_registration_QueryInterface,
386 local_mft_registration_AddRef,
387 local_mft_registration_Release,
388 local_mft_registration_RegisterMFTs,
391 static IMFLocalMFTRegistration local_mft_registration = { &local_mft_registration_vtbl };
393 static HRESULT WINAPI session_op_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
395 if (IsEqualIID(riid, &IID_IUnknown))
397 *obj = iface;
398 IUnknown_AddRef(iface);
399 return S_OK;
402 *obj = NULL;
403 return E_NOINTERFACE;
406 static ULONG WINAPI session_op_AddRef(IUnknown *iface)
408 struct session_op *op = impl_op_from_IUnknown(iface);
409 ULONG refcount = InterlockedIncrement(&op->refcount);
411 TRACE("%p, refcount %u.\n", iface, refcount);
413 return refcount;
416 static ULONG WINAPI session_op_Release(IUnknown *iface)
418 struct session_op *op = impl_op_from_IUnknown(iface);
419 ULONG refcount = InterlockedDecrement(&op->refcount);
421 TRACE("%p, refcount %u.\n", iface, refcount);
423 if (!refcount)
425 switch (op->command)
427 case SESSION_CMD_SET_TOPOLOGY:
428 if (op->u.set_topology.topology)
429 IMFTopology_Release(op->u.set_topology.topology);
430 break;
431 case SESSION_CMD_START:
432 PropVariantClear(&op->u.start.start_position);
433 break;
434 case SESSION_CMD_QM_NOTIFY_TOPOLOGY:
435 if (op->u.notify_topology.topology)
436 IMFTopology_Release(op->u.notify_topology.topology);
437 break;
438 default:
441 free(op);
444 return refcount;
447 static const IUnknownVtbl session_op_vtbl =
449 session_op_QueryInterface,
450 session_op_AddRef,
451 session_op_Release,
454 static HRESULT create_session_op(enum session_command command, struct session_op **ret)
456 struct session_op *op;
458 if (!(op = calloc(1, sizeof(*op))))
459 return E_OUTOFMEMORY;
461 op->IUnknown_iface.lpVtbl = &session_op_vtbl;
462 op->refcount = 1;
463 op->command = command;
465 *ret = op;
467 return S_OK;
470 static HRESULT session_is_shut_down(struct media_session *session)
472 return session->state == SESSION_STATE_SHUT_DOWN ? MF_E_SHUTDOWN : S_OK;
475 static void session_push_back_command(struct media_session *session, enum session_command command)
477 struct session_op *op;
479 if (SUCCEEDED(create_session_op(command, &op)))
480 list_add_head(&session->commands, &op->entry);
483 static HRESULT session_submit_command(struct media_session *session, struct session_op *op)
485 HRESULT hr;
487 EnterCriticalSection(&session->cs);
488 if (SUCCEEDED(hr = session_is_shut_down(session)))
490 if (list_empty(&session->commands))
491 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface);
492 list_add_tail(&session->commands, &op->entry);
493 IUnknown_AddRef(&op->IUnknown_iface);
495 LeaveCriticalSection(&session->cs);
497 return hr;
500 static HRESULT session_submit_simple_command(struct media_session *session, enum session_command command)
502 struct session_op *op;
503 HRESULT hr;
505 if (FAILED(hr = create_session_op(command, &op)))
506 return hr;
508 hr = session_submit_command(session, op);
509 IUnknown_Release(&op->IUnknown_iface);
510 return hr;
513 static void session_clear_queued_topologies(struct media_session *session)
515 struct queued_topology *ptr, *next;
517 LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &session->topologies, struct queued_topology, entry)
519 list_remove(&ptr->entry);
520 IMFTopology_Release(ptr->topology);
521 free(ptr);
525 static void session_set_topo_status(struct media_session *session, HRESULT status,
526 MF_TOPOSTATUS topo_status)
528 IMFMediaEvent *event;
529 PROPVARIANT param;
531 if (topo_status == MF_TOPOSTATUS_INVALID)
532 return;
534 if (list_empty(&session->topologies))
536 FIXME("Unexpectedly empty topology queue.\n");
537 return;
540 if (topo_status > session->presentation.topo_status)
542 struct queued_topology *topology = LIST_ENTRY(list_head(&session->topologies), struct queued_topology, entry);
544 param.vt = VT_UNKNOWN;
545 param.punkVal = (IUnknown *)topology->topology;
547 if (FAILED(MFCreateMediaEvent(MESessionTopologyStatus, &GUID_NULL, status, &param, &event)))
548 return;
550 session->presentation.topo_status = topo_status;
552 IMFMediaEvent_SetUINT32(event, &MF_EVENT_TOPOLOGY_STATUS, topo_status);
553 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
554 IMFMediaEvent_Release(event);
558 static HRESULT session_bind_output_nodes(IMFTopology *topology)
560 MF_TOPOLOGY_TYPE node_type;
561 IMFStreamSink *stream_sink;
562 IMFMediaSink *media_sink;
563 WORD node_count = 0, i;
564 IMFTopologyNode *node;
565 IMFActivate *activate;
566 UINT32 stream_id;
567 IUnknown *object;
568 HRESULT hr;
570 hr = IMFTopology_GetNodeCount(topology, &node_count);
572 for (i = 0; i < node_count; ++i)
574 if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
575 break;
577 if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type)) || node_type != MF_TOPOLOGY_OUTPUT_NODE)
579 IMFTopologyNode_Release(node);
580 continue;
583 if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object)))
585 stream_sink = NULL;
586 if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&stream_sink)))
588 if (SUCCEEDED(hr = IUnknown_QueryInterface(object, &IID_IMFActivate, (void **)&activate)))
590 if (SUCCEEDED(hr = IMFActivate_ActivateObject(activate, &IID_IMFMediaSink, (void **)&media_sink)))
592 if (FAILED(IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_STREAMID, &stream_id)))
593 stream_id = 0;
595 stream_sink = NULL;
596 if (FAILED(IMFMediaSink_GetStreamSinkById(media_sink, stream_id, &stream_sink)))
597 hr = IMFMediaSink_AddStreamSink(media_sink, stream_id, NULL, &stream_sink);
599 if (stream_sink)
600 hr = IMFTopologyNode_SetObject(node, (IUnknown *)stream_sink);
602 IMFMediaSink_Release(media_sink);
605 if (SUCCEEDED(hr))
606 IMFTopologyNode_SetUnknown(node, &_MF_TOPONODE_IMFActivate, (IUnknown *)activate);
608 IMFActivate_Release(activate);
612 if (stream_sink)
613 IMFStreamSink_Release(stream_sink);
614 IUnknown_Release(object);
617 IMFTopologyNode_Release(node);
620 return hr;
623 static void session_set_caps(struct media_session *session, DWORD caps)
625 DWORD delta = session->caps ^ caps;
626 IMFMediaEvent *event;
628 /* Delta is documented to reflect rate value changes as well, but it's not clear what to compare
629 them to, since session always queries for current object rates. */
630 if (!delta)
631 return;
633 session->caps = caps;
635 if (FAILED(MFCreateMediaEvent(MESessionCapabilitiesChanged, &GUID_NULL, S_OK, NULL, &event)))
636 return;
638 IMFMediaEvent_SetUINT32(event, &MF_EVENT_SESSIONCAPS, caps);
639 IMFMediaEvent_SetUINT32(event, &MF_EVENT_SESSIONCAPS_DELTA, delta);
641 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
642 IMFMediaEvent_Release(event);
645 static void transform_release_sample(struct sample *sample)
647 list_remove(&sample->entry);
648 if (sample->sample)
649 IMFSample_Release(sample->sample);
650 free(sample);
653 static void transform_stream_drop_samples(struct transform_stream *stream)
655 struct sample *sample, *sample2;
657 LIST_FOR_EACH_ENTRY_SAFE(sample, sample2, &stream->samples, struct sample, entry)
658 transform_release_sample(sample);
661 static void release_topo_node(struct topo_node *node)
663 unsigned int i;
665 switch (node->type)
667 case MF_TOPOLOGY_SOURCESTREAM_NODE:
668 if (node->u.source.source)
669 IMFMediaSource_Release(node->u.source.source);
670 break;
671 case MF_TOPOLOGY_TRANSFORM_NODE:
672 for (i = 0; i < node->u.transform.input_count; ++i)
673 transform_stream_drop_samples(&node->u.transform.inputs[i]);
674 for (i = 0; i < node->u.transform.output_count; ++i)
675 transform_stream_drop_samples(&node->u.transform.outputs[i]);
676 free(node->u.transform.inputs);
677 free(node->u.transform.outputs);
678 free(node->u.transform.input_map);
679 free(node->u.transform.output_map);
680 break;
681 case MF_TOPOLOGY_OUTPUT_NODE:
682 if (node->u.sink.allocator)
683 IMFVideoSampleAllocator_Release(node->u.sink.allocator);
684 if (node->u.sink.allocator_cb)
686 IMFVideoSampleAllocatorCallback_SetCallback(node->u.sink.allocator_cb, NULL);
687 IMFVideoSampleAllocatorCallback_Release(node->u.sink.allocator_cb);
689 break;
690 default:
694 if (node->object.object)
695 IUnknown_Release(node->object.object);
696 if (node->node)
697 IMFTopologyNode_Release(node->node);
698 free(node);
701 static void session_shutdown_current_topology(struct media_session *session)
703 unsigned int shutdown, force_shutdown;
704 MF_TOPOLOGY_TYPE node_type;
705 IMFStreamSink *stream_sink;
706 IMFTopology *topology;
707 IMFTopologyNode *node;
708 IMFActivate *activate;
709 IMFMediaSink *sink;
710 WORD idx = 0;
711 HRESULT hr;
713 topology = session->presentation.current_topology;
714 force_shutdown = session->state == SESSION_STATE_SHUT_DOWN;
716 /* FIXME: should handle async MFTs, but these are not supported by the rest of the pipeline currently. */
718 while (SUCCEEDED(IMFTopology_GetNode(topology, idx++, &node)))
720 if (SUCCEEDED(IMFTopologyNode_GetNodeType(node, &node_type)) &&
721 node_type == MF_TOPOLOGY_OUTPUT_NODE)
723 shutdown = 1;
724 IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, &shutdown);
726 if (force_shutdown || shutdown)
728 if (SUCCEEDED(IMFTopologyNode_GetUnknown(node, &_MF_TOPONODE_IMFActivate, &IID_IMFActivate,
729 (void **)&activate)))
731 if (FAILED(hr = IMFActivate_ShutdownObject(activate)))
732 WARN("Failed to shut down activation object for the sink, hr %#x.\n", hr);
733 IMFActivate_Release(activate);
735 else if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink)))
737 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink)))
739 IMFMediaSink_Shutdown(sink);
740 IMFMediaSink_Release(sink);
743 IMFStreamSink_Release(stream_sink);
748 IMFTopologyNode_Release(node);
752 static void session_clear_command_list(struct media_session *session)
754 struct session_op *op, *op2;
756 LIST_FOR_EACH_ENTRY_SAFE(op, op2, &session->commands, struct session_op, entry)
758 list_remove(&op->entry);
759 IUnknown_Release(&op->IUnknown_iface);
763 static void session_clear_presentation(struct media_session *session)
765 struct media_source *source, *source2;
766 struct media_sink *sink, *sink2;
767 struct topo_node *node, *node2;
769 session_shutdown_current_topology(session);
771 IMFTopology_Clear(session->presentation.current_topology);
772 session->presentation.topo_status = MF_TOPOSTATUS_INVALID;
774 LIST_FOR_EACH_ENTRY_SAFE(source, source2, &session->presentation.sources, struct media_source, entry)
776 list_remove(&source->entry);
777 if (source->source)
778 IMFMediaSource_Release(source->source);
779 if (source->pd)
780 IMFPresentationDescriptor_Release(source->pd);
781 free(source);
784 LIST_FOR_EACH_ENTRY_SAFE(node, node2, &session->presentation.nodes, struct topo_node, entry)
786 list_remove(&node->entry);
787 release_topo_node(node);
790 LIST_FOR_EACH_ENTRY_SAFE(sink, sink2, &session->presentation.sinks, struct media_sink, entry)
792 list_remove(&sink->entry);
794 if (sink->sink)
795 IMFMediaSink_Release(sink->sink);
796 if (sink->preroll)
797 IMFMediaSinkPreroll_Release(sink->preroll);
798 if (sink->event_generator)
799 IMFMediaEventGenerator_Release(sink->event_generator);
800 free(sink);
804 static struct topo_node *session_get_node_by_id(const struct media_session *session, TOPOID id)
806 struct topo_node *node;
808 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
810 if (node->node_id == id)
811 return node;
814 return NULL;
817 static void session_command_complete(struct media_session *session)
819 struct session_op *op;
820 struct list *e;
822 /* Pop current command, submit next. */
823 if ((e = list_head(&session->commands)))
825 op = LIST_ENTRY(e, struct session_op, entry);
826 list_remove(&op->entry);
827 IUnknown_Release(&op->IUnknown_iface);
830 if ((e = list_head(&session->commands)))
832 op = LIST_ENTRY(e, struct session_op, entry);
833 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface);
837 static void session_command_complete_with_event(struct media_session *session, MediaEventType event,
838 HRESULT status, const PROPVARIANT *param)
840 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, event, &GUID_NULL, status, param);
841 session_command_complete(session);
844 static void session_start(struct media_session *session, const GUID *time_format, const PROPVARIANT *start_position)
846 struct media_source *source;
847 HRESULT hr;
849 switch (session->state)
851 case SESSION_STATE_STOPPED:
853 /* Start request with no current topology. */
854 if (session->presentation.topo_status == MF_TOPOSTATUS_INVALID)
856 session_command_complete_with_event(session, MESessionStarted, MF_E_INVALIDREQUEST, NULL);
857 break;
860 /* fallthrough */
861 case SESSION_STATE_PAUSED:
863 session->presentation.time_format = *time_format;
864 session->presentation.start_position.vt = VT_EMPTY;
865 PropVariantCopy(&session->presentation.start_position, start_position);
867 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
869 if (!(session->presentation.flags & SESSION_FLAG_SOURCES_SUBSCRIBED))
871 if (FAILED(hr = IMFMediaSource_BeginGetEvent(source->source, &session->events_callback,
872 source->object)))
874 WARN("Failed to subscribe to source events, hr %#x.\n", hr);
878 if (FAILED(hr = IMFMediaSource_Start(source->source, source->pd, &GUID_NULL, start_position)))
879 WARN("Failed to start media source %p, hr %#x.\n", source->source, hr);
882 session->presentation.flags |= SESSION_FLAG_SOURCES_SUBSCRIBED;
883 session->state = SESSION_STATE_STARTING_SOURCES;
884 break;
885 case SESSION_STATE_STARTED:
886 FIXME("Seeking is not implemented.\n");
887 session_command_complete(session);
888 break;
889 default:
890 session_command_complete_with_event(session, MESessionStarted, MF_E_INVALIDREQUEST, NULL);
891 break;
895 static void session_set_started(struct media_session *session)
897 struct media_source *source;
898 unsigned int caps, flags;
899 IMFMediaEvent *event;
901 session->state = SESSION_STATE_STARTED;
903 caps = session->caps | MFSESSIONCAP_PAUSE;
905 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
907 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source->source, &flags)))
909 if (!(flags & MFMEDIASOURCE_CAN_PAUSE))
911 caps &= ~MFSESSIONCAP_PAUSE;
912 break;
917 session_set_caps(session, caps);
919 if (SUCCEEDED(MFCreateMediaEvent(MESessionStarted, &GUID_NULL, S_OK, NULL, &event)))
921 IMFMediaEvent_SetUINT64(event, &MF_EVENT_PRESENTATION_TIME_OFFSET, 0);
922 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
923 IMFMediaEvent_Release(event);
925 session_command_complete(session);
928 static void session_set_paused(struct media_session *session, unsigned int state, HRESULT status)
930 /* Failed event status could indicate a failure during normal transition to paused state,
931 or an attempt to pause from invalid initial state. To finalize failed transition in the former case,
932 state is still forced to PAUSED, otherwise previous state is retained. */
933 if (state != ~0u) session->state = state;
934 if (SUCCEEDED(status))
935 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
936 session_command_complete_with_event(session, MESessionPaused, status, NULL);
939 static void session_set_closed(struct media_session *session, HRESULT status)
941 session->state = SESSION_STATE_CLOSED;
942 if (SUCCEEDED(status))
943 session_set_caps(session, session->caps & ~(MFSESSIONCAP_START | MFSESSIONCAP_SEEK));
944 session_command_complete_with_event(session, MESessionClosed, status, NULL);
947 static void session_pause(struct media_session *session)
949 unsigned int state = ~0u;
950 HRESULT hr;
952 switch (session->state)
954 case SESSION_STATE_STARTED:
956 /* Transition in two steps - pause the clock, wait for sinks, then pause sources. */
957 if (SUCCEEDED(hr = IMFPresentationClock_Pause(session->clock)))
958 session->state = SESSION_STATE_PAUSING_SINKS;
959 state = SESSION_STATE_PAUSED;
961 break;
963 case SESSION_STATE_STOPPED:
964 hr = MF_E_SESSION_PAUSEWHILESTOPPED;
965 break;
966 default:
967 hr = MF_E_INVALIDREQUEST;
970 if (FAILED(hr))
971 session_set_paused(session, state, hr);
974 static void session_clear_end_of_presentation(struct media_session *session)
976 struct media_source *source;
977 struct topo_node *node;
979 session->presentation.flags &= ~SESSION_FLAG_END_OF_PRESENTATION;
980 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
982 source->flags &= ~SOURCE_FLAG_END_OF_PRESENTATION;
984 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
986 node->flags &= ~TOPO_NODE_END_OF_STREAM;
988 session->presentation.topo_status = MF_TOPOSTATUS_READY;
991 static void session_set_stopped(struct media_session *session, HRESULT status)
993 MediaEventType event_type;
994 IMFMediaEvent *event;
996 session->state = SESSION_STATE_STOPPED;
997 event_type = session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION ? MESessionEnded : MESessionStopped;
999 if (SUCCEEDED(MFCreateMediaEvent(event_type, &GUID_NULL, status, NULL, &event)))
1001 IMFMediaEvent_SetUINT64(event, &MF_SESSION_APPROX_EVENT_OCCURRENCE_TIME, session->presentation.clock_stop_time);
1002 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
1003 IMFMediaEvent_Release(event);
1005 session_clear_end_of_presentation(session);
1006 session_command_complete(session);
1009 static void session_stop(struct media_session *session)
1011 HRESULT hr = MF_E_INVALIDREQUEST;
1013 switch (session->state)
1015 case SESSION_STATE_STARTED:
1016 case SESSION_STATE_PAUSED:
1018 /* Transition in two steps - stop the clock, wait for sinks, then stop sources. */
1019 IMFPresentationClock_GetTime(session->clock, &session->presentation.clock_stop_time);
1020 if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock)))
1021 session->state = SESSION_STATE_STOPPING_SINKS;
1022 else
1023 session_set_stopped(session, hr);
1025 break;
1026 case SESSION_STATE_STOPPED:
1027 hr = S_OK;
1028 /* fallthrough */
1029 default:
1030 session_command_complete_with_event(session, MESessionStopped, hr, NULL);
1031 break;
1035 static HRESULT session_finalize_sinks(struct media_session *session)
1037 IMFFinalizableMediaSink *fin_sink;
1038 BOOL sinks_finalized = TRUE;
1039 struct media_sink *sink;
1040 HRESULT hr = S_OK;
1042 session->presentation.flags &= ~SESSION_FLAG_FINALIZE_SINKS;
1043 session->state = SESSION_STATE_FINALIZING_SINKS;
1045 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
1047 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink->sink, &IID_IMFFinalizableMediaSink, (void **)&fin_sink)))
1049 hr = IMFFinalizableMediaSink_BeginFinalize(fin_sink, &session->sink_finalizer_callback,
1050 (IUnknown *)fin_sink);
1051 IMFFinalizableMediaSink_Release(fin_sink);
1052 if (FAILED(hr))
1053 break;
1054 sinks_finalized = FALSE;
1056 else
1057 sink->finalized = TRUE;
1060 if (sinks_finalized)
1061 session_set_closed(session, hr);
1063 return hr;
1066 static void session_close(struct media_session *session)
1068 HRESULT hr = S_OK;
1070 switch (session->state)
1072 case SESSION_STATE_STOPPED:
1073 hr = session_finalize_sinks(session);
1074 break;
1075 case SESSION_STATE_STARTED:
1076 case SESSION_STATE_PAUSED:
1077 session->presentation.flags |= SESSION_FLAG_FINALIZE_SINKS;
1078 if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock)))
1079 session->state = SESSION_STATE_STOPPING_SINKS;
1080 break;
1081 default:
1082 hr = MF_E_INVALIDREQUEST;
1083 break;
1086 session_clear_queued_topologies(session);
1087 if (FAILED(hr))
1088 session_set_closed(session, hr);
1091 static void session_clear_topologies(struct media_session *session)
1093 HRESULT hr = S_OK;
1095 if (session->state == SESSION_STATE_CLOSED)
1096 hr = MF_E_INVALIDREQUEST;
1097 else
1098 session_clear_queued_topologies(session);
1099 session_command_complete_with_event(session, MESessionTopologiesCleared, hr, NULL);
1102 static struct media_source *session_get_media_source(struct media_session *session, IMFMediaSource *source)
1104 struct media_source *cur;
1106 LIST_FOR_EACH_ENTRY(cur, &session->presentation.sources, struct media_source, entry)
1108 if (source == cur->source)
1109 return cur;
1112 return NULL;
1115 static void session_release_media_source(struct media_source *source)
1117 IMFMediaSource_Release(source->source);
1118 if (source->pd)
1119 IMFPresentationDescriptor_Release(source->pd);
1120 free(source);
1123 static HRESULT session_add_media_source(struct media_session *session, IMFTopologyNode *node, IMFMediaSource *source)
1125 struct media_source *media_source;
1126 HRESULT hr;
1128 if (session_get_media_source(session, source))
1129 return S_FALSE;
1131 if (!(media_source = calloc(1, sizeof(*media_source))))
1132 return E_OUTOFMEMORY;
1134 media_source->source = source;
1135 IMFMediaSource_AddRef(media_source->source);
1137 hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, &IID_IMFPresentationDescriptor,
1138 (void **)&media_source->pd);
1140 if (SUCCEEDED(hr))
1141 list_add_tail(&session->presentation.sources, &media_source->entry);
1142 else
1143 session_release_media_source(media_source);
1145 return hr;
1148 static void session_raise_topology_set(struct media_session *session, IMFTopology *topology, HRESULT status)
1150 PROPVARIANT param;
1152 param.vt = topology ? VT_UNKNOWN : VT_EMPTY;
1153 param.punkVal = (IUnknown *)topology;
1155 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologySet, &GUID_NULL, status, &param);
1158 static DWORD session_get_object_rate_caps(IUnknown *object)
1160 IMFRateSupport *rate_support;
1161 DWORD caps = 0;
1162 float rate;
1164 if (SUCCEEDED(MFGetService(object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support)))
1166 rate = 0.0f;
1167 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support, MFRATE_FORWARD, TRUE, &rate)) && rate != 0.0f)
1168 caps |= MFSESSIONCAP_RATE_FORWARD;
1170 rate = 0.0f;
1171 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support, MFRATE_REVERSE, TRUE, &rate)) && rate != 0.0f)
1172 caps |= MFSESSIONCAP_RATE_REVERSE;
1174 IMFRateSupport_Release(rate_support);
1177 return caps;
1180 static HRESULT session_add_media_sink(struct media_session *session, IMFTopologyNode *node, IMFMediaSink *sink)
1182 struct media_sink *media_sink;
1183 unsigned int disable_preroll = 0;
1184 DWORD flags;
1186 LIST_FOR_EACH_ENTRY(media_sink, &session->presentation.sinks, struct media_sink, entry)
1188 if (sink == media_sink->sink)
1189 return S_FALSE;
1192 if (!(media_sink = calloc(1, sizeof(*media_sink))))
1193 return E_OUTOFMEMORY;
1195 media_sink->sink = sink;
1196 IMFMediaSink_AddRef(media_sink->sink);
1198 IMFMediaSink_QueryInterface(media_sink->sink, &IID_IMFMediaEventGenerator, (void **)&media_sink->event_generator);
1200 IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_DISABLE_PREROLL, &disable_preroll);
1201 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink, &flags)) && flags & MEDIASINK_CAN_PREROLL && !disable_preroll)
1203 if (SUCCEEDED(IMFMediaSink_QueryInterface(media_sink->sink, &IID_IMFMediaSinkPreroll, (void **)&media_sink->preroll)))
1204 session->presentation.flags |= SESSION_FLAG_NEEDS_PREROLL;
1207 list_add_tail(&session->presentation.sinks, &media_sink->entry);
1209 return S_OK;
1212 static unsigned int transform_node_get_stream_id(struct topo_node *node, BOOL output, unsigned int index)
1214 unsigned int *map = output ? node->u.transform.output_map : node->u.transform.input_map;
1215 return map ? map[index] : index;
1218 static HRESULT session_set_transform_stream_info(struct topo_node *node)
1220 unsigned int *input_map = NULL, *output_map = NULL;
1221 unsigned int i, input_count, output_count, block_alignment;
1222 struct transform_stream *streams;
1223 IMFMediaType *media_type;
1224 GUID major = { 0 };
1225 HRESULT hr;
1227 hr = IMFTransform_GetStreamCount(node->object.transform, &input_count, &output_count);
1228 if (SUCCEEDED(hr) && (input_count > 1 || output_count > 1))
1230 input_map = calloc(input_count, sizeof(*input_map));
1231 output_map = calloc(output_count, sizeof(*output_map));
1232 if (FAILED(IMFTransform_GetStreamIDs(node->object.transform, input_count, input_map,
1233 output_count, output_map)))
1235 /* Assume sequential identifiers. */
1236 free(input_map);
1237 free(output_map);
1238 input_map = output_map = NULL;
1242 if (SUCCEEDED(hr))
1244 node->u.transform.input_map = input_map;
1245 node->u.transform.output_map = output_map;
1247 streams = calloc(input_count, sizeof(*streams));
1248 for (i = 0; i < input_count; ++i)
1249 list_init(&streams[i].samples);
1250 node->u.transform.inputs = streams;
1251 node->u.transform.input_count = input_count;
1253 streams = calloc(output_count, sizeof(*streams));
1254 for (i = 0; i < output_count; ++i)
1256 list_init(&streams[i].samples);
1258 if (SUCCEEDED(IMFTransform_GetOutputCurrentType(node->object.transform,
1259 transform_node_get_stream_id(node, TRUE, i), &media_type)))
1261 if (SUCCEEDED(IMFMediaType_GetMajorType(media_type, &major)) && IsEqualGUID(&major, &MFMediaType_Audio)
1262 && SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment)))
1264 streams[i].min_buffer_size = block_alignment;
1266 IMFMediaType_Release(media_type);
1269 node->u.transform.outputs = streams;
1270 node->u.transform.output_count = output_count;
1273 return hr;
1276 static HRESULT session_get_stream_sink_type(IMFStreamSink *sink, IMFMediaType **media_type)
1278 IMFMediaTypeHandler *handler;
1279 HRESULT hr;
1281 if (SUCCEEDED(hr = IMFStreamSink_GetMediaTypeHandler(sink, &handler)))
1283 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, media_type);
1284 IMFMediaTypeHandler_Release(handler);
1287 return hr;
1290 static HRESULT WINAPI node_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify *iface,
1291 REFIID riid, void **obj)
1293 if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorNotify) ||
1294 IsEqualIID(riid, &IID_IUnknown))
1296 *obj = iface;
1297 IMFVideoSampleAllocatorNotify_AddRef(iface);
1298 return S_OK;
1301 *obj = NULL;
1302 return E_NOINTERFACE;
1305 static ULONG WINAPI node_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify *iface)
1307 return 2;
1310 static ULONG WINAPI node_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify *iface)
1312 return 1;
1315 static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output);
1317 static HRESULT WINAPI node_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify *iface)
1319 struct topo_node *topo_node = impl_node_from_IMFVideoSampleAllocatorNotify(iface);
1320 struct session_op *op;
1322 if (SUCCEEDED(create_session_op(SESSION_CMD_SA_READY, &op)))
1324 op->u.sa_ready.node_id = topo_node->node_id;
1325 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &topo_node->session->commands_callback, &op->IUnknown_iface);
1326 IUnknown_Release(&op->IUnknown_iface);
1329 return S_OK;
1332 static const IMFVideoSampleAllocatorNotifyVtbl node_sample_allocator_cb_vtbl =
1334 node_sample_allocator_cb_QueryInterface,
1335 node_sample_allocator_cb_AddRef,
1336 node_sample_allocator_cb_Release,
1337 node_sample_allocator_cb_NotifyRelease,
1340 static HRESULT session_append_node(struct media_session *session, IMFTopologyNode *node)
1342 struct topo_node *topo_node;
1343 IMFMediaSink *media_sink;
1344 IMFMediaType *media_type;
1345 IMFStreamDescriptor *sd;
1346 HRESULT hr = S_OK;
1348 if (!(topo_node = calloc(1, sizeof(*topo_node))))
1349 return E_OUTOFMEMORY;
1351 IMFTopologyNode_GetNodeType(node, &topo_node->type);
1352 IMFTopologyNode_GetTopoNodeID(node, &topo_node->node_id);
1353 topo_node->node = node;
1354 IMFTopologyNode_AddRef(topo_node->node);
1355 topo_node->session = session;
1357 switch (topo_node->type)
1359 case MF_TOPOLOGY_OUTPUT_NODE:
1360 topo_node->u.sink.notify_cb.lpVtbl = &node_sample_allocator_cb_vtbl;
1362 if (FAILED(hr = topology_node_get_object(node, &IID_IMFStreamSink, (void **)&topo_node->object.object)))
1364 WARN("Failed to get stream sink interface, hr %#x.\n", hr);
1365 break;
1368 if (FAILED(hr = IMFStreamSink_GetMediaSink(topo_node->object.sink_stream, &media_sink)))
1369 break;
1371 if (SUCCEEDED(hr = session_add_media_sink(session, node, media_sink)))
1373 if (SUCCEEDED(session_get_stream_sink_type(topo_node->object.sink_stream, &media_type)))
1375 if (SUCCEEDED(MFGetService(topo_node->object.object, &MR_VIDEO_ACCELERATION_SERVICE,
1376 &IID_IMFVideoSampleAllocator, (void **)&topo_node->u.sink.allocator)))
1378 if (FAILED(hr = IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node->u.sink.allocator,
1379 2, media_type)))
1381 WARN("Failed to initialize sample allocator for the stream, hr %#x.\n", hr);
1383 IMFVideoSampleAllocator_QueryInterface(topo_node->u.sink.allocator,
1384 &IID_IMFVideoSampleAllocatorCallback, (void **)&topo_node->u.sink.allocator_cb);
1385 IMFVideoSampleAllocatorCallback_SetCallback(topo_node->u.sink.allocator_cb,
1386 &topo_node->u.sink.notify_cb);
1388 IMFMediaType_Release(media_type);
1391 IMFMediaSink_Release(media_sink);
1393 break;
1394 case MF_TOPOLOGY_SOURCESTREAM_NODE:
1395 if (FAILED(IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_SOURCE, &IID_IMFMediaSource,
1396 (void **)&topo_node->u.source.source)))
1398 WARN("Missing MF_TOPONODE_SOURCE, hr %#x.\n", hr);
1399 break;
1402 if (FAILED(hr = session_add_media_source(session, node, topo_node->u.source.source)))
1403 break;
1405 if (FAILED(hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR,
1406 &IID_IMFStreamDescriptor, (void **)&sd)))
1408 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#x.\n", hr);
1409 break;
1412 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &topo_node->u.source.stream_id);
1413 IMFStreamDescriptor_Release(sd);
1415 break;
1416 case MF_TOPOLOGY_TRANSFORM_NODE:
1418 if (SUCCEEDED(hr = topology_node_get_object(node, &IID_IMFTransform, (void **)&topo_node->object.transform)))
1420 hr = session_set_transform_stream_info(topo_node);
1422 else
1423 WARN("Failed to get IMFTransform for MFT node, hr %#x.\n", hr);
1425 break;
1426 case MF_TOPOLOGY_TEE_NODE:
1427 FIXME("Unsupported node type %d.\n", topo_node->type);
1429 break;
1430 default:
1434 if (SUCCEEDED(hr))
1435 list_add_tail(&session->presentation.nodes, &topo_node->entry);
1436 else
1437 release_topo_node(topo_node);
1439 return hr;
1442 static HRESULT session_collect_nodes(struct media_session *session)
1444 IMFTopology *topology = session->presentation.current_topology;
1445 IMFTopologyNode *node;
1446 WORD i, count = 0;
1447 HRESULT hr;
1449 if (!list_empty(&session->presentation.nodes))
1450 return S_OK;
1452 if (FAILED(hr = IMFTopology_GetNodeCount(topology, &count)))
1453 return hr;
1455 for (i = 0; i < count; ++i)
1457 if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
1459 WARN("Failed to get node %u.\n", i);
1460 break;
1463 hr = session_append_node(session, node);
1464 IMFTopologyNode_Release(node);
1465 if (FAILED(hr))
1467 WARN("Failed to add node %u.\n", i);
1468 break;
1472 return hr;
1475 static HRESULT session_set_current_topology(struct media_session *session, IMFTopology *topology)
1477 struct media_source *source;
1478 DWORD caps, object_flags;
1479 struct media_sink *sink;
1480 struct topo_node *node;
1481 struct session_op *op;
1482 IMFMediaEvent *event;
1483 HRESULT hr;
1485 if (session->quality_manager)
1487 if (SUCCEEDED(create_session_op(SESSION_CMD_QM_NOTIFY_TOPOLOGY, &op)))
1489 op->u.notify_topology.topology = topology;
1490 IMFTopology_AddRef(op->u.notify_topology.topology);
1491 session_submit_command(session, op);
1492 IUnknown_Release(&op->IUnknown_iface);
1496 if (FAILED(hr = IMFTopology_CloneFrom(session->presentation.current_topology, topology)))
1498 WARN("Failed to clone topology, hr %#x.\n", hr);
1499 return hr;
1502 session_collect_nodes(session);
1504 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
1506 if (node->type == MF_TOPOLOGY_TRANSFORM_NODE)
1508 if (FAILED(hr = IMFTransform_ProcessMessage(node->object.transform,
1509 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0)))
1510 return hr;
1514 /* FIXME: attributes are all zero for now */
1515 if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime, &GUID_NULL, S_OK, NULL, &event)))
1517 IMFMediaEvent_SetUINT64(event, &MF_EVENT_START_PRESENTATION_TIME, 0);
1518 IMFMediaEvent_SetUINT64(event, &MF_EVENT_PRESENTATION_TIME_OFFSET, 0);
1519 IMFMediaEvent_SetUINT64(event, &MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT, 0);
1521 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
1522 IMFMediaEvent_Release(event);
1525 /* Update session caps. */
1526 caps = MFSESSIONCAP_START | MFSESSIONCAP_SEEK | MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE |
1527 MFSESSIONCAP_DOES_NOT_USE_NETWORK;
1529 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
1531 if (!caps)
1532 break;
1534 object_flags = 0;
1535 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source->source, &object_flags)))
1537 if (!(object_flags & MFMEDIASOURCE_DOES_NOT_USE_NETWORK))
1538 caps &= ~MFSESSIONCAP_DOES_NOT_USE_NETWORK;
1539 if (!(object_flags & MFMEDIASOURCE_CAN_SEEK))
1540 caps &= ~MFSESSIONCAP_SEEK;
1543 /* Mask unsupported rate caps. */
1545 caps &= session_get_object_rate_caps(source->object)
1546 | ~(MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE);
1549 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
1551 if (!caps)
1552 break;
1554 object_flags = 0;
1555 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink->sink, &object_flags)))
1557 if (!(object_flags & MEDIASINK_RATELESS))
1558 caps &= session_get_object_rate_caps(sink->object)
1559 | ~(MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE);
1563 session_set_caps(session, caps);
1565 return S_OK;
1568 static void session_set_topology(struct media_session *session, DWORD flags, IMFTopology *topology)
1570 IMFTopology *resolved_topology = NULL;
1571 HRESULT hr = S_OK;
1573 /* Resolve unless claimed to be full. */
1574 if (!(flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT) && topology)
1576 if (!(flags & MFSESSION_SETTOPOLOGY_NORESOLUTION))
1578 hr = session_bind_output_nodes(topology);
1580 if (SUCCEEDED(hr))
1581 hr = IMFTopoLoader_Load(session->topo_loader, topology, &resolved_topology, NULL /* FIXME? */);
1583 if (SUCCEEDED(hr))
1585 topology = resolved_topology;
1590 if (flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT)
1592 if ((topology && topology == session->presentation.current_topology) || !topology)
1594 /* FIXME: stop current topology, queue next one. */
1595 session_clear_presentation(session);
1597 else
1598 hr = S_FALSE;
1600 topology = NULL;
1602 else if (topology && flags & MFSESSION_SETTOPOLOGY_IMMEDIATE)
1604 session_clear_queued_topologies(session);
1605 session_clear_presentation(session);
1608 session_raise_topology_set(session, topology, hr);
1610 /* With no current topology set it right away, otherwise queue. */
1611 if (topology)
1613 struct queued_topology *queued_topology;
1615 if ((queued_topology = calloc(1, sizeof(*queued_topology))))
1617 queued_topology->topology = topology;
1618 IMFTopology_AddRef(queued_topology->topology);
1620 list_add_tail(&session->topologies, &queued_topology->entry);
1623 if (session->presentation.topo_status == MF_TOPOSTATUS_INVALID)
1625 hr = session_set_current_topology(session, topology);
1626 session_set_topo_status(session, hr, MF_TOPOSTATUS_READY);
1630 if (resolved_topology)
1631 IMFTopology_Release(resolved_topology);
1634 static HRESULT WINAPI mfsession_QueryInterface(IMFMediaSession *iface, REFIID riid, void **out)
1636 struct media_session *session = impl_from_IMFMediaSession(iface);
1638 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1640 *out = NULL;
1642 if (IsEqualIID(riid, &IID_IMFMediaSession) ||
1643 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
1644 IsEqualIID(riid, &IID_IUnknown))
1646 *out = &session->IMFMediaSession_iface;
1648 else if (IsEqualIID(riid, &IID_IMFGetService))
1650 *out = &session->IMFGetService_iface;
1652 else if (IsEqualIID(riid, &IID_IMFRateSupport))
1654 *out = &session->IMFRateSupport_iface;
1656 else if (IsEqualIID(riid, &IID_IMFRateControl))
1658 *out = &session->IMFRateControl_iface;
1661 if (*out)
1663 IMFMediaSession_AddRef(iface);
1664 return S_OK;
1667 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1668 return E_NOINTERFACE;
1671 static ULONG WINAPI mfsession_AddRef(IMFMediaSession *iface)
1673 struct media_session *session = impl_from_IMFMediaSession(iface);
1674 ULONG refcount = InterlockedIncrement(&session->refcount);
1676 TRACE("%p, refcount %u.\n", iface, refcount);
1678 return refcount;
1681 static ULONG WINAPI mfsession_Release(IMFMediaSession *iface)
1683 struct media_session *session = impl_from_IMFMediaSession(iface);
1684 ULONG refcount = InterlockedDecrement(&session->refcount);
1686 TRACE("%p, refcount %u.\n", iface, refcount);
1688 if (!refcount)
1690 session_clear_queued_topologies(session);
1691 session_clear_presentation(session);
1692 session_clear_command_list(session);
1693 if (session->presentation.current_topology)
1694 IMFTopology_Release(session->presentation.current_topology);
1695 if (session->event_queue)
1696 IMFMediaEventQueue_Release(session->event_queue);
1697 if (session->clock)
1698 IMFPresentationClock_Release(session->clock);
1699 if (session->system_time_source)
1700 IMFPresentationTimeSource_Release(session->system_time_source);
1701 if (session->clock_rate_control)
1702 IMFRateControl_Release(session->clock_rate_control);
1703 if (session->topo_loader)
1704 IMFTopoLoader_Release(session->topo_loader);
1705 if (session->quality_manager)
1706 IMFQualityManager_Release(session->quality_manager);
1707 DeleteCriticalSection(&session->cs);
1708 free(session);
1711 return refcount;
1714 static HRESULT WINAPI mfsession_GetEvent(IMFMediaSession *iface, DWORD flags, IMFMediaEvent **event)
1716 struct media_session *session = impl_from_IMFMediaSession(iface);
1718 TRACE("%p, %#x, %p.\n", iface, flags, event);
1720 return IMFMediaEventQueue_GetEvent(session->event_queue, flags, event);
1723 static HRESULT WINAPI mfsession_BeginGetEvent(IMFMediaSession *iface, IMFAsyncCallback *callback, IUnknown *state)
1725 struct media_session *session = impl_from_IMFMediaSession(iface);
1727 TRACE("%p, %p, %p.\n", iface, callback, state);
1729 return IMFMediaEventQueue_BeginGetEvent(session->event_queue, callback, state);
1732 static HRESULT WINAPI mfsession_EndGetEvent(IMFMediaSession *iface, IMFAsyncResult *result, IMFMediaEvent **event)
1734 struct media_session *session = impl_from_IMFMediaSession(iface);
1736 TRACE("%p, %p, %p.\n", iface, result, event);
1738 return IMFMediaEventQueue_EndGetEvent(session->event_queue, result, event);
1741 static HRESULT WINAPI mfsession_QueueEvent(IMFMediaSession *iface, MediaEventType event_type, REFGUID ext_type,
1742 HRESULT hr, const PROPVARIANT *value)
1744 struct media_session *session = impl_from_IMFMediaSession(iface);
1746 TRACE("%p, %d, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
1748 return IMFMediaEventQueue_QueueEventParamVar(session->event_queue, event_type, ext_type, hr, value);
1751 static HRESULT WINAPI mfsession_SetTopology(IMFMediaSession *iface, DWORD flags, IMFTopology *topology)
1753 struct media_session *session = impl_from_IMFMediaSession(iface);
1754 struct session_op *op;
1755 WORD node_count = 0;
1756 HRESULT hr;
1758 TRACE("%p, %#x, %p.\n", iface, flags, topology);
1760 if (topology)
1762 if (FAILED(IMFTopology_GetNodeCount(topology, &node_count)) || node_count == 0)
1763 return E_INVALIDARG;
1766 if (FAILED(hr = create_session_op(SESSION_CMD_SET_TOPOLOGY, &op)))
1767 return hr;
1769 op->u.set_topology.flags = flags;
1770 op->u.set_topology.topology = topology;
1771 if (op->u.set_topology.topology)
1772 IMFTopology_AddRef(op->u.set_topology.topology);
1774 hr = session_submit_command(session, op);
1775 IUnknown_Release(&op->IUnknown_iface);
1777 return hr;
1780 static HRESULT WINAPI mfsession_ClearTopologies(IMFMediaSession *iface)
1782 struct media_session *session = impl_from_IMFMediaSession(iface);
1784 TRACE("%p.\n", iface);
1786 return session_submit_simple_command(session, SESSION_CMD_CLEAR_TOPOLOGIES);
1789 static HRESULT WINAPI mfsession_Start(IMFMediaSession *iface, const GUID *format, const PROPVARIANT *start_position)
1791 struct media_session *session = impl_from_IMFMediaSession(iface);
1792 struct session_op *op;
1793 HRESULT hr;
1795 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), start_position);
1797 if (!start_position)
1798 return E_POINTER;
1800 if (FAILED(hr = create_session_op(SESSION_CMD_START, &op)))
1801 return hr;
1803 op->u.start.time_format = format ? *format : GUID_NULL;
1804 hr = PropVariantCopy(&op->u.start.start_position, start_position);
1806 if (SUCCEEDED(hr))
1807 hr = session_submit_command(session, op);
1809 IUnknown_Release(&op->IUnknown_iface);
1810 return hr;
1813 static HRESULT WINAPI mfsession_Pause(IMFMediaSession *iface)
1815 struct media_session *session = impl_from_IMFMediaSession(iface);
1817 TRACE("%p.\n", iface);
1819 return session_submit_simple_command(session, SESSION_CMD_PAUSE);
1822 static HRESULT WINAPI mfsession_Stop(IMFMediaSession *iface)
1824 struct media_session *session = impl_from_IMFMediaSession(iface);
1826 TRACE("%p.\n", iface);
1828 return session_submit_simple_command(session, SESSION_CMD_STOP);
1831 static HRESULT WINAPI mfsession_Close(IMFMediaSession *iface)
1833 struct media_session *session = impl_from_IMFMediaSession(iface);
1835 TRACE("%p.\n", iface);
1837 return session_submit_simple_command(session, SESSION_CMD_CLOSE);
1840 static HRESULT WINAPI mfsession_Shutdown(IMFMediaSession *iface)
1842 struct media_session *session = impl_from_IMFMediaSession(iface);
1843 HRESULT hr = S_OK;
1845 TRACE("%p.\n", iface);
1847 EnterCriticalSection(&session->cs);
1848 if (SUCCEEDED(hr = session_is_shut_down(session)))
1850 session->state = SESSION_STATE_SHUT_DOWN;
1851 IMFMediaEventQueue_Shutdown(session->event_queue);
1852 if (session->quality_manager)
1853 IMFQualityManager_Shutdown(session->quality_manager);
1854 MFShutdownObject((IUnknown *)session->clock);
1855 IMFPresentationClock_Release(session->clock);
1856 session->clock = NULL;
1857 session_clear_presentation(session);
1858 session_clear_command_list(session);
1860 LeaveCriticalSection(&session->cs);
1862 return hr;
1865 static HRESULT WINAPI mfsession_GetClock(IMFMediaSession *iface, IMFClock **clock)
1867 struct media_session *session = impl_from_IMFMediaSession(iface);
1868 HRESULT hr;
1870 TRACE("%p, %p.\n", iface, clock);
1872 EnterCriticalSection(&session->cs);
1873 if (SUCCEEDED(hr = session_is_shut_down(session)))
1875 *clock = (IMFClock *)session->clock;
1876 IMFClock_AddRef(*clock);
1878 LeaveCriticalSection(&session->cs);
1880 return hr;
1883 static HRESULT WINAPI mfsession_GetSessionCapabilities(IMFMediaSession *iface, DWORD *caps)
1885 struct media_session *session = impl_from_IMFMediaSession(iface);
1886 HRESULT hr = S_OK;
1888 TRACE("%p, %p.\n", iface, caps);
1890 if (!caps)
1891 return E_POINTER;
1893 EnterCriticalSection(&session->cs);
1894 if (SUCCEEDED(hr = session_is_shut_down(session)))
1895 *caps = session->caps;
1896 LeaveCriticalSection(&session->cs);
1898 return hr;
1901 static HRESULT WINAPI mfsession_GetFullTopology(IMFMediaSession *iface, DWORD flags, TOPOID id, IMFTopology **topology)
1903 struct media_session *session = impl_from_IMFMediaSession(iface);
1904 struct queued_topology *queued;
1905 TOPOID topo_id;
1906 HRESULT hr;
1908 TRACE("%p, %#x, %s, %p.\n", iface, flags, wine_dbgstr_longlong(id), topology);
1910 *topology = NULL;
1912 EnterCriticalSection(&session->cs);
1914 if (SUCCEEDED(hr = session_is_shut_down(session)))
1916 if (flags & MFSESSION_GETFULLTOPOLOGY_CURRENT)
1918 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
1919 *topology = session->presentation.current_topology;
1920 else
1921 hr = MF_E_INVALIDREQUEST;
1923 else
1925 LIST_FOR_EACH_ENTRY(queued, &session->topologies, struct queued_topology, entry)
1927 if (SUCCEEDED(IMFTopology_GetTopologyID(queued->topology, &topo_id)) && topo_id == id)
1929 *topology = queued->topology;
1930 break;
1935 if (*topology)
1936 IMFTopology_AddRef(*topology);
1939 LeaveCriticalSection(&session->cs);
1941 return hr;
1944 static const IMFMediaSessionVtbl mfmediasessionvtbl =
1946 mfsession_QueryInterface,
1947 mfsession_AddRef,
1948 mfsession_Release,
1949 mfsession_GetEvent,
1950 mfsession_BeginGetEvent,
1951 mfsession_EndGetEvent,
1952 mfsession_QueueEvent,
1953 mfsession_SetTopology,
1954 mfsession_ClearTopologies,
1955 mfsession_Start,
1956 mfsession_Pause,
1957 mfsession_Stop,
1958 mfsession_Close,
1959 mfsession_Shutdown,
1960 mfsession_GetClock,
1961 mfsession_GetSessionCapabilities,
1962 mfsession_GetFullTopology,
1965 static HRESULT WINAPI session_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1967 struct media_session *session = impl_from_IMFGetService(iface);
1968 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
1971 static ULONG WINAPI session_get_service_AddRef(IMFGetService *iface)
1973 struct media_session *session = impl_from_IMFGetService(iface);
1974 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
1977 static ULONG WINAPI session_get_service_Release(IMFGetService *iface)
1979 struct media_session *session = impl_from_IMFGetService(iface);
1980 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
1983 typedef BOOL (*p_renderer_node_test_func)(IMFMediaSink *sink);
1985 static BOOL session_video_renderer_test_func(IMFMediaSink *sink)
1987 IUnknown *obj;
1988 HRESULT hr;
1990 /* Use first sink to support IMFVideoRenderer. */
1991 hr = IMFMediaSink_QueryInterface(sink, &IID_IMFVideoRenderer, (void **)&obj);
1992 if (obj)
1993 IUnknown_Release(obj);
1995 return hr == S_OK;
1998 static BOOL session_audio_renderer_test_func(IMFMediaSink *sink)
2000 return mf_is_sar_sink(sink);
2003 static HRESULT session_get_renderer_node_service(struct media_session *session,
2004 p_renderer_node_test_func node_test_func, REFGUID service, REFIID riid, void **obj)
2006 HRESULT hr = E_NOINTERFACE;
2007 IMFStreamSink *stream_sink;
2008 IMFTopologyNode *node;
2009 IMFCollection *nodes;
2010 IMFMediaSink *sink;
2011 unsigned int i = 0;
2013 if (session->presentation.current_topology)
2015 if (SUCCEEDED(IMFTopology_GetOutputNodeCollection(session->presentation.current_topology,
2016 &nodes)))
2018 while (IMFCollection_GetElement(nodes, i++, (IUnknown **)&node) == S_OK)
2020 if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink)))
2022 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink)))
2024 if (node_test_func(sink))
2026 if (FAILED(hr = MFGetService((IUnknown *)sink, service, riid, obj)))
2027 WARN("Failed to get service from renderer node, %#x.\n", hr);
2030 IMFStreamSink_Release(stream_sink);
2033 IMFTopologyNode_Release(node);
2035 if (*obj)
2036 break;
2039 IMFCollection_Release(nodes);
2043 return hr;
2046 static HRESULT session_get_audio_render_service(struct media_session *session, REFGUID service,
2047 REFIID riid, void **obj)
2049 return session_get_renderer_node_service(session, session_audio_renderer_test_func,
2050 service, riid, obj);
2053 static HRESULT session_get_video_render_service(struct media_session *session, REFGUID service,
2054 REFIID riid, void **obj)
2056 return session_get_renderer_node_service(session, session_video_renderer_test_func,
2057 service, riid, obj);
2060 static HRESULT WINAPI session_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
2062 struct media_session *session = impl_from_IMFGetService(iface);
2063 HRESULT hr = S_OK;
2065 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
2067 *obj = NULL;
2069 EnterCriticalSection(&session->cs);
2070 if (FAILED(hr = session_is_shut_down(session)))
2073 else if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE))
2075 if (IsEqualIID(riid, &IID_IMFRateSupport))
2077 *obj = &session->IMFRateSupport_iface;
2079 else if (IsEqualIID(riid, &IID_IMFRateControl))
2081 *obj = &session->IMFRateControl_iface;
2083 else
2084 hr = E_NOINTERFACE;
2086 if (*obj)
2087 IUnknown_AddRef((IUnknown *)*obj);
2089 else if (IsEqualGUID(service, &MF_LOCAL_MFT_REGISTRATION_SERVICE))
2091 hr = IMFLocalMFTRegistration_QueryInterface(&local_mft_registration, riid, obj);
2093 else if (IsEqualGUID(service, &MF_TOPONODE_ATTRIBUTE_EDITOR_SERVICE))
2095 *obj = &session->IMFTopologyNodeAttributeEditor_iface;
2096 IUnknown_AddRef((IUnknown *)*obj);
2098 else if (IsEqualGUID(service, &MR_VIDEO_RENDER_SERVICE))
2100 hr = session_get_video_render_service(session, service, riid, obj);
2102 else if (IsEqualGUID(service, &MR_POLICY_VOLUME_SERVICE) ||
2103 IsEqualGUID(service, &MR_STREAM_VOLUME_SERVICE))
2105 hr = session_get_audio_render_service(session, service, riid, obj);
2107 else
2108 FIXME("Unsupported service %s.\n", debugstr_guid(service));
2110 LeaveCriticalSection(&session->cs);
2112 return hr;
2115 static const IMFGetServiceVtbl session_get_service_vtbl =
2117 session_get_service_QueryInterface,
2118 session_get_service_AddRef,
2119 session_get_service_Release,
2120 session_get_service_GetService,
2123 static HRESULT WINAPI session_commands_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
2125 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
2126 IsEqualIID(riid, &IID_IUnknown))
2128 *obj = iface;
2129 IMFAsyncCallback_AddRef(iface);
2130 return S_OK;
2133 WARN("Unsupported %s.\n", debugstr_guid(riid));
2134 *obj = NULL;
2135 return E_NOINTERFACE;
2138 static ULONG WINAPI session_commands_callback_AddRef(IMFAsyncCallback *iface)
2140 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2141 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2144 static ULONG WINAPI session_commands_callback_Release(IMFAsyncCallback *iface)
2146 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2147 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2150 static HRESULT WINAPI session_commands_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
2152 return E_NOTIMPL;
2155 static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
2157 struct session_op *op = impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result));
2158 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2159 struct topo_node *topo_node;
2160 IMFTopologyNode *upstream_node;
2161 unsigned int upstream_output;
2163 EnterCriticalSection(&session->cs);
2165 switch (op->command)
2167 case SESSION_CMD_CLEAR_TOPOLOGIES:
2168 session_clear_topologies(session);
2169 break;
2170 case SESSION_CMD_SET_TOPOLOGY:
2171 session_set_topology(session, op->u.set_topology.flags, op->u.set_topology.topology);
2172 session_command_complete(session);
2173 break;
2174 case SESSION_CMD_START:
2175 session_start(session, &op->u.start.time_format, &op->u.start.start_position);
2176 break;
2177 case SESSION_CMD_PAUSE:
2178 session_pause(session);
2179 break;
2180 case SESSION_CMD_STOP:
2181 session_stop(session);
2182 break;
2183 case SESSION_CMD_CLOSE:
2184 session_close(session);
2185 break;
2186 case SESSION_CMD_QM_NOTIFY_TOPOLOGY:
2187 IMFQualityManager_NotifyTopology(session->quality_manager, op->u.notify_topology.topology);
2188 session_command_complete(session);
2189 break;
2190 case SESSION_CMD_SA_READY:
2191 topo_node = session_get_node_by_id(session, op->u.sa_ready.node_id);
2193 if (topo_node->u.sink.requests)
2195 if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node->node, 0, &upstream_node, &upstream_output)))
2197 session_request_sample_from_node(session, upstream_node, upstream_output);
2198 IMFTopologyNode_Release(upstream_node);
2201 break;
2202 default:
2206 LeaveCriticalSection(&session->cs);
2208 return S_OK;
2211 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl =
2213 session_commands_callback_QueryInterface,
2214 session_commands_callback_AddRef,
2215 session_commands_callback_Release,
2216 session_commands_callback_GetParameters,
2217 session_commands_callback_Invoke,
2220 static HRESULT WINAPI session_events_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
2222 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
2223 IsEqualIID(riid, &IID_IUnknown))
2225 *obj = iface;
2226 IMFAsyncCallback_AddRef(iface);
2227 return S_OK;
2230 WARN("Unsupported %s.\n", debugstr_guid(riid));
2231 *obj = NULL;
2232 return E_NOINTERFACE;
2235 static ULONG WINAPI session_events_callback_AddRef(IMFAsyncCallback *iface)
2237 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
2238 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2241 static ULONG WINAPI session_events_callback_Release(IMFAsyncCallback *iface)
2243 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
2244 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2247 static HRESULT WINAPI session_events_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
2249 return E_NOTIMPL;
2252 static HRESULT session_add_media_stream(struct media_session *session, IMFMediaSource *source, IMFMediaStream *stream)
2254 struct topo_node *node;
2255 IMFStreamDescriptor *sd;
2256 DWORD stream_id = 0;
2257 HRESULT hr;
2259 if (FAILED(hr = IMFMediaStream_GetStreamDescriptor(stream, &sd)))
2260 return hr;
2262 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &stream_id);
2263 IMFStreamDescriptor_Release(sd);
2264 if (FAILED(hr))
2265 return hr;
2267 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2269 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->u.source.source == source
2270 && node->u.source.stream_id == stream_id)
2272 if (node->object.source_stream)
2274 WARN("Node already has stream set.\n");
2275 return S_FALSE;
2278 node->object.source_stream = stream;
2279 IMFMediaStream_AddRef(node->object.source_stream);
2280 break;
2284 return S_OK;
2287 static BOOL session_is_source_nodes_state(struct media_session *session, enum object_state state)
2289 struct media_source *source;
2290 struct topo_node *node;
2292 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2294 if (source->state != state)
2295 return FALSE;
2298 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2300 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->state != state)
2301 return FALSE;
2304 return TRUE;
2307 static BOOL session_is_output_nodes_state(struct media_session *session, enum object_state state)
2309 struct topo_node *node;
2311 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2313 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->state != state)
2314 return FALSE;
2317 return TRUE;
2320 static enum object_state session_get_object_state_for_event(MediaEventType event)
2322 switch (event)
2324 case MESourceStarted:
2325 case MEStreamStarted:
2326 case MEStreamSinkStarted:
2327 return OBJ_STATE_STARTED;
2328 case MESourcePaused:
2329 case MEStreamPaused:
2330 case MEStreamSinkPaused:
2331 return OBJ_STATE_PAUSED;
2332 case MESourceStopped:
2333 case MEStreamStopped:
2334 case MEStreamSinkStopped:
2335 return OBJ_STATE_STOPPED;
2336 case MEStreamSinkPrerolled:
2337 return OBJ_STATE_PREROLLED;
2338 default:
2339 return OBJ_STATE_INVALID;
2343 static void session_set_consumed_clock(IUnknown *object, IMFPresentationClock *clock)
2345 IMFClockConsumer *consumer;
2347 if (SUCCEEDED(IUnknown_QueryInterface(object, &IID_IMFClockConsumer, (void **)&consumer)))
2349 IMFClockConsumer_SetPresentationClock(consumer, clock);
2350 IMFClockConsumer_Release(consumer);
2354 static void session_set_presentation_clock(struct media_session *session)
2356 IMFPresentationTimeSource *time_source = NULL;
2357 struct media_source *source;
2358 struct media_sink *sink;
2359 struct topo_node *node;
2360 HRESULT hr;
2362 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2364 if (node->type == MF_TOPOLOGY_TRANSFORM_NODE)
2365 IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
2368 if (!(session->presentation.flags & SESSION_FLAG_PRESENTATION_CLOCK_SET))
2370 /* Attempt to get time source from the sinks. */
2371 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2373 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink->sink, &IID_IMFPresentationTimeSource,
2374 (void **)&time_source)))
2375 break;
2378 if (time_source)
2380 hr = IMFPresentationClock_SetTimeSource(session->clock, time_source);
2381 IMFPresentationTimeSource_Release(time_source);
2383 else
2384 hr = IMFPresentationClock_SetTimeSource(session->clock, session->system_time_source);
2386 if (FAILED(hr))
2387 WARN("Failed to set time source, hr %#x.\n", hr);
2389 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2391 if (node->type != MF_TOPOLOGY_OUTPUT_NODE)
2392 continue;
2394 if (FAILED(hr = IMFStreamSink_BeginGetEvent(node->object.sink_stream, &session->events_callback,
2395 node->object.object)))
2397 WARN("Failed to subscribe to stream sink events, hr %#x.\n", hr);
2401 /* Set clock for all topology nodes. */
2402 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2404 session_set_consumed_clock(source->object, session->clock);
2407 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2409 if (sink->event_generator && FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(sink->event_generator,
2410 &session->events_callback, (IUnknown *)sink->event_generator)))
2412 WARN("Failed to subscribe to sink events, hr %#x.\n", hr);
2415 if (FAILED(hr = IMFMediaSink_SetPresentationClock(sink->sink, session->clock)))
2416 WARN("Failed to set presentation clock for the sink, hr %#x.\n", hr);
2419 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2421 if (node->type != MF_TOPOLOGY_TRANSFORM_NODE)
2422 continue;
2424 session_set_consumed_clock(node->object.object, session->clock);
2427 session->presentation.flags |= SESSION_FLAG_PRESENTATION_CLOCK_SET;
2431 static HRESULT session_start_clock(struct media_session *session)
2433 LONGLONG start_offset = 0;
2434 HRESULT hr;
2436 if (IsEqualGUID(&session->presentation.time_format, &GUID_NULL))
2438 if (session->presentation.start_position.vt == VT_EMPTY)
2439 start_offset = PRESENTATION_CURRENT_POSITION;
2440 else if (session->presentation.start_position.vt == VT_I8)
2441 start_offset = session->presentation.start_position.hVal.QuadPart;
2442 else
2443 FIXME("Unhandled position type %d.\n", session->presentation.start_position.vt);
2445 else
2446 FIXME("Unhandled time format %s.\n", debugstr_guid(&session->presentation.time_format));
2448 if (FAILED(hr = IMFPresentationClock_Start(session->clock, start_offset)))
2449 WARN("Failed to start session clock, hr %#x.\n", hr);
2451 return hr;
2454 static struct topo_node *session_get_node_object(struct media_session *session, IUnknown *object,
2455 MF_TOPOLOGY_TYPE node_type)
2457 struct topo_node *node = NULL;
2459 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2461 if (node->type == node_type && object == node->object.object)
2462 break;
2465 return node;
2468 static BOOL session_set_node_object_state(struct media_session *session, IUnknown *object,
2469 MF_TOPOLOGY_TYPE node_type, enum object_state state)
2471 struct topo_node *node;
2472 BOOL changed = FALSE;
2474 if ((node = session_get_node_object(session, object, node_type)))
2476 changed = node->state != state;
2477 node->state = state;
2480 return changed;
2483 static void session_set_source_object_state(struct media_session *session, IUnknown *object,
2484 MediaEventType event_type)
2486 IMFStreamSink *stream_sink;
2487 struct media_source *src;
2488 struct media_sink *sink;
2489 enum object_state state;
2490 struct topo_node *node;
2491 unsigned int i, count;
2492 BOOL changed = FALSE;
2493 HRESULT hr;
2495 if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
2496 return;
2498 switch (event_type)
2500 case MESourceStarted:
2501 case MESourcePaused:
2502 case MESourceStopped:
2504 LIST_FOR_EACH_ENTRY(src, &session->presentation.sources, struct media_source, entry)
2506 if (object == src->object)
2508 changed = src->state != state;
2509 src->state = state;
2510 break;
2513 break;
2514 case MEStreamStarted:
2515 case MEStreamPaused:
2516 case MEStreamStopped:
2518 changed = session_set_node_object_state(session, object, MF_TOPOLOGY_SOURCESTREAM_NODE, state);
2519 default:
2523 if (!changed)
2524 return;
2526 switch (session->state)
2528 case SESSION_STATE_STARTING_SOURCES:
2529 if (!session_is_source_nodes_state(session, OBJ_STATE_STARTED))
2530 break;
2532 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_STARTED_SOURCE);
2534 session_set_presentation_clock(session);
2536 if (session->presentation.flags & SESSION_FLAG_NEEDS_PREROLL)
2538 MFTIME preroll_time = 0;
2540 if (session->presentation.start_position.vt == VT_I8)
2541 preroll_time = session->presentation.start_position.hVal.QuadPart;
2543 /* Mark stream sinks without prerolling support as PREROLLED to keep state test logic generic. */
2544 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2546 if (sink->preroll)
2548 /* FIXME: abort and enter error state on failure. */
2549 if (FAILED(hr = IMFMediaSinkPreroll_NotifyPreroll(sink->preroll, preroll_time)))
2550 WARN("Preroll notification failed, hr %#x.\n", hr);
2552 else
2554 if (SUCCEEDED(IMFMediaSink_GetStreamSinkCount(sink->sink, &count)))
2556 for (i = 0; i < count; ++i)
2558 if (SUCCEEDED(IMFMediaSink_GetStreamSinkByIndex(sink->sink, i, &stream_sink)))
2560 session_set_node_object_state(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE,
2561 OBJ_STATE_PREROLLED);
2562 IMFStreamSink_Release(stream_sink);
2568 session->state = SESSION_STATE_PREROLLING_SINKS;
2570 else if (SUCCEEDED(session_start_clock(session)))
2571 session->state = SESSION_STATE_STARTING_SINKS;
2573 break;
2574 case SESSION_STATE_PAUSING_SOURCES:
2575 if (!session_is_source_nodes_state(session, OBJ_STATE_PAUSED))
2576 break;
2578 session_set_paused(session, SESSION_STATE_PAUSED, S_OK);
2579 break;
2580 case SESSION_STATE_STOPPING_SOURCES:
2581 if (!session_is_source_nodes_state(session, OBJ_STATE_STOPPED))
2582 break;
2584 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2586 switch (node->type)
2588 case MF_TOPOLOGY_OUTPUT_NODE:
2589 IMFStreamSink_Flush(node->object.sink_stream);
2590 break;
2591 case MF_TOPOLOGY_TRANSFORM_NODE:
2592 IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_COMMAND_FLUSH, 0);
2593 break;
2594 default:
2599 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
2601 if (session->presentation.flags & SESSION_FLAG_FINALIZE_SINKS)
2602 session_finalize_sinks(session);
2603 else
2604 session_set_stopped(session, S_OK);
2606 break;
2607 default:
2612 static void session_set_sink_stream_state(struct media_session *session, IMFStreamSink *stream,
2613 MediaEventType event_type)
2615 struct media_source *source;
2616 enum object_state state;
2617 HRESULT hr = S_OK;
2618 BOOL changed;
2620 if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
2621 return;
2623 if (!(changed = session_set_node_object_state(session, (IUnknown *)stream, MF_TOPOLOGY_OUTPUT_NODE, state)))
2624 return;
2626 switch (session->state)
2628 case SESSION_STATE_PREROLLING_SINKS:
2629 if (!session_is_output_nodes_state(session, OBJ_STATE_PREROLLED))
2630 break;
2632 if (SUCCEEDED(session_start_clock(session)))
2633 session->state = SESSION_STATE_STARTING_SINKS;
2634 break;
2635 case SESSION_STATE_STARTING_SINKS:
2636 if (!session_is_output_nodes_state(session, OBJ_STATE_STARTED))
2637 break;
2639 session_set_started(session);
2640 break;
2641 case SESSION_STATE_PAUSING_SINKS:
2642 if (!session_is_output_nodes_state(session, OBJ_STATE_PAUSED))
2643 break;
2645 session->state = SESSION_STATE_PAUSING_SOURCES;
2647 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2649 if (FAILED(hr = IMFMediaSource_Pause(source->source)))
2650 break;
2653 if (FAILED(hr))
2654 session_set_paused(session, SESSION_STATE_PAUSED, hr);
2656 break;
2657 case SESSION_STATE_STOPPING_SINKS:
2658 if (!session_is_output_nodes_state(session, OBJ_STATE_STOPPED))
2659 break;
2661 session->state = SESSION_STATE_STOPPING_SOURCES;
2663 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2665 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION)
2666 IMFMediaSource_Stop(source->source);
2667 else if (FAILED(hr = IMFMediaSource_Stop(source->source)))
2668 break;
2671 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION || FAILED(hr))
2672 session_set_stopped(session, hr);
2674 break;
2675 default:
2680 static struct sample *transform_create_sample(IMFSample *sample)
2682 struct sample *sample_entry = calloc(1, sizeof(*sample_entry));
2684 if (sample_entry)
2686 sample_entry->sample = sample;
2687 if (sample_entry->sample)
2688 IMFSample_AddRef(sample_entry->sample);
2691 return sample_entry;
2694 static HRESULT transform_get_external_output_sample(const struct media_session *session, struct topo_node *transform,
2695 unsigned int output_index, const MFT_OUTPUT_STREAM_INFO *stream_info, IMFSample **sample)
2697 unsigned int buffer_size, downstream_input;
2698 IMFTopologyNode *downstream_node;
2699 IMFMediaBuffer *buffer = NULL;
2700 struct topo_node *topo_node;
2701 TOPOID node_id;
2702 HRESULT hr;
2704 if (FAILED(IMFTopologyNode_GetOutput(transform->node, output_index, &downstream_node, &downstream_input)))
2706 WARN("Failed to get connected node for output %u.\n", output_index);
2707 return MF_E_UNEXPECTED;
2710 IMFTopologyNode_GetTopoNodeID(downstream_node, &node_id);
2711 IMFTopologyNode_Release(downstream_node);
2713 topo_node = session_get_node_by_id(session, node_id);
2715 if (topo_node->type == MF_TOPOLOGY_OUTPUT_NODE && topo_node->u.sink.allocator)
2717 hr = IMFVideoSampleAllocator_AllocateSample(topo_node->u.sink.allocator, sample);
2719 else
2721 buffer_size = max(stream_info->cbSize, transform->u.transform.outputs[output_index].min_buffer_size);
2723 hr = MFCreateAlignedMemoryBuffer(buffer_size, stream_info->cbAlignment, &buffer);
2724 if (SUCCEEDED(hr))
2725 hr = MFCreateSample(sample);
2727 if (SUCCEEDED(hr))
2728 hr = IMFSample_AddBuffer(*sample, buffer);
2730 if (buffer)
2731 IMFMediaBuffer_Release(buffer);
2734 return hr;
2737 static HRESULT transform_node_pull_samples(const struct media_session *session, struct topo_node *node)
2739 MFT_OUTPUT_STREAM_INFO stream_info;
2740 MFT_OUTPUT_DATA_BUFFER *buffers;
2741 struct sample *queued_sample;
2742 DWORD status = 0;
2743 unsigned int i;
2744 HRESULT hr = E_UNEXPECTED;
2746 if (!(buffers = calloc(node->u.transform.output_count, sizeof(*buffers))))
2747 return E_OUTOFMEMORY;
2749 for (i = 0; i < node->u.transform.output_count; ++i)
2751 buffers[i].dwStreamID = transform_node_get_stream_id(node, TRUE, i);
2752 buffers[i].pSample = NULL;
2753 buffers[i].dwStatus = 0;
2754 buffers[i].pEvents = NULL;
2756 memset(&stream_info, 0, sizeof(stream_info));
2757 if (FAILED(hr = IMFTransform_GetOutputStreamInfo(node->object.transform, buffers[i].dwStreamID, &stream_info)))
2758 break;
2760 if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)))
2762 if (FAILED(hr = transform_get_external_output_sample(session, node, i, &stream_info, &buffers[i].pSample)))
2763 break;
2767 if (SUCCEEDED(hr))
2768 hr = IMFTransform_ProcessOutput(node->object.transform, 0, node->u.transform.output_count, buffers, &status);
2770 /* Collect returned samples for all streams. */
2771 for (i = 0; i < node->u.transform.output_count; ++i)
2773 if (buffers[i].pEvents)
2774 IMFCollection_Release(buffers[i].pEvents);
2776 if (SUCCEEDED(hr) && !(buffers[i].dwStatus & MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE))
2778 if (session->quality_manager)
2779 IMFQualityManager_NotifyProcessOutput(session->quality_manager, node->node, i, buffers[i].pSample);
2781 queued_sample = transform_create_sample(buffers[i].pSample);
2782 list_add_tail(&node->u.transform.outputs[i].samples, &queued_sample->entry);
2785 if (buffers[i].pSample)
2786 IMFSample_Release(buffers[i].pSample);
2789 free(buffers);
2791 return hr;
2794 static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input,
2795 IMFSample *sample)
2797 struct sample *sample_entry, *sample_entry2;
2798 DWORD stream_id, downstream_input;
2799 IMFTopologyNode *downstream_node;
2800 struct topo_node *topo_node;
2801 MF_TOPOLOGY_TYPE node_type;
2802 BOOL drain = FALSE;
2803 TOPOID node_id;
2804 unsigned int i;
2805 HRESULT hr;
2807 if (session->quality_manager)
2808 IMFQualityManager_NotifyProcessInput(session->quality_manager, node, input, sample);
2810 IMFTopologyNode_GetNodeType(node, &node_type);
2811 IMFTopologyNode_GetTopoNodeID(node, &node_id);
2813 topo_node = session_get_node_by_id(session, node_id);
2815 switch (node_type)
2817 case MF_TOPOLOGY_OUTPUT_NODE:
2818 if (sample)
2820 if (topo_node->u.sink.requests)
2822 if (FAILED(hr = IMFStreamSink_ProcessSample(topo_node->object.sink_stream, sample)))
2823 WARN("Stream sink failed to process sample, hr %#x.\n", hr);
2824 topo_node->u.sink.requests--;
2827 else if (FAILED(hr = IMFStreamSink_PlaceMarker(topo_node->object.sink_stream, MFSTREAMSINK_MARKER_ENDOFSEGMENT,
2828 NULL, NULL)))
2830 WARN("Failed to place sink marker, hr %#x.\n", hr);
2832 break;
2833 case MF_TOPOLOGY_TRANSFORM_NODE:
2835 transform_node_pull_samples(session, topo_node);
2837 sample_entry = transform_create_sample(sample);
2838 list_add_tail(&topo_node->u.transform.inputs[input].samples, &sample_entry->entry);
2840 for (i = 0; i < topo_node->u.transform.input_count; ++i)
2842 stream_id = transform_node_get_stream_id(topo_node, FALSE, i);
2843 LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.inputs[i].samples,
2844 struct sample, entry)
2846 if (sample_entry->sample)
2848 if ((hr = IMFTransform_ProcessInput(topo_node->object.transform, stream_id,
2849 sample_entry->sample, 0)) == MF_E_NOTACCEPTING)
2850 break;
2851 if (FAILED(hr))
2852 WARN("Failed to process input for stream %u/%u, hr %#x.\n", i, stream_id, hr);
2853 transform_release_sample(sample_entry);
2855 else
2857 transform_stream_drop_samples(&topo_node->u.transform.inputs[i]);
2858 drain = TRUE;
2863 if (drain)
2865 if (FAILED(hr = IMFTransform_ProcessMessage(topo_node->object.transform, MFT_MESSAGE_COMMAND_DRAIN, 0)))
2866 WARN("Drain command failed for transform, hr %#x.\n", hr);
2869 transform_node_pull_samples(session, topo_node);
2871 /* Remaining unprocessed input has been discarded, now queue markers for every output. */
2872 if (drain)
2874 for (i = 0; i < topo_node->u.transform.output_count; ++i)
2876 if ((sample_entry = transform_create_sample(NULL)))
2877 list_add_tail(&topo_node->u.transform.outputs[i].samples, &sample_entry->entry);
2881 /* Push down all available output. */
2882 for (i = 0; i < topo_node->u.transform.output_count; ++i)
2884 if (FAILED(IMFTopologyNode_GetOutput(node, i, &downstream_node, &downstream_input)))
2886 WARN("Failed to get connected node for output %u.\n", i);
2887 continue;
2890 LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.outputs[i].samples,
2891 struct sample, entry)
2893 if (!topo_node->u.transform.outputs[i].requests)
2894 break;
2896 session_deliver_sample_to_node(session, downstream_node, downstream_input, sample_entry->sample);
2897 topo_node->u.transform.outputs[i].requests--;
2899 transform_release_sample(sample_entry);
2902 IMFTopologyNode_Release(downstream_node);
2905 break;
2906 case MF_TOPOLOGY_TEE_NODE:
2907 FIXME("Unhandled downstream node type %d.\n", node_type);
2908 break;
2909 default:
2914 static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output)
2916 IMFTopologyNode *downstream_node, *upstream_node;
2917 unsigned int downstream_input, upstream_output;
2918 struct topo_node *topo_node;
2919 MF_TOPOLOGY_TYPE node_type;
2920 struct sample *sample;
2921 TOPOID node_id;
2922 HRESULT hr;
2924 IMFTopologyNode_GetNodeType(node, &node_type);
2925 IMFTopologyNode_GetTopoNodeID(node, &node_id);
2927 topo_node = session_get_node_by_id(session, node_id);
2929 switch (node_type)
2931 case MF_TOPOLOGY_SOURCESTREAM_NODE:
2932 if (FAILED(hr = IMFMediaStream_RequestSample(topo_node->object.source_stream, NULL)))
2933 WARN("Sample request failed, hr %#x.\n", hr);
2934 break;
2935 case MF_TOPOLOGY_TRANSFORM_NODE:
2937 if (list_empty(&topo_node->u.transform.outputs[output].samples))
2939 /* Forward request to upstream node. */
2940 if (SUCCEEDED(hr = IMFTopologyNode_GetInput(node, 0 /* FIXME */, &upstream_node, &upstream_output)))
2942 if (SUCCEEDED(hr = session_request_sample_from_node(session, upstream_node, upstream_output)))
2943 topo_node->u.transform.outputs[output].requests++;
2944 IMFTopologyNode_Release(upstream_node);
2947 else
2949 if (SUCCEEDED(hr = IMFTopologyNode_GetOutput(node, output, &downstream_node, &downstream_input)))
2951 sample = LIST_ENTRY(list_head(&topo_node->u.transform.outputs[output].samples), struct sample, entry);
2952 session_deliver_sample_to_node(session, downstream_node, downstream_input, sample->sample);
2953 transform_release_sample(sample);
2954 IMFTopologyNode_Release(downstream_node);
2958 break;
2959 case MF_TOPOLOGY_TEE_NODE:
2960 FIXME("Unhandled upstream node type %d.\n", node_type);
2961 default:
2962 hr = E_UNEXPECTED;
2965 return hr;
2968 static void session_request_sample(struct media_session *session, IMFStreamSink *sink_stream)
2970 struct topo_node *sink_node = NULL, *node;
2971 IMFTopologyNode *upstream_node;
2972 DWORD upstream_output;
2973 HRESULT hr;
2975 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2977 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink_stream)
2979 sink_node = node;
2980 break;
2984 if (!sink_node)
2985 return;
2987 if (FAILED(hr = IMFTopologyNode_GetInput(sink_node->node, 0, &upstream_node, &upstream_output)))
2989 WARN("Failed to get upstream node connection, hr %#x.\n", hr);
2990 return;
2993 if (SUCCEEDED(session_request_sample_from_node(session, upstream_node, upstream_output)))
2994 sink_node->u.sink.requests++;
2995 IMFTopologyNode_Release(upstream_node);
2998 static void session_deliver_sample(struct media_session *session, IMFMediaStream *stream, const PROPVARIANT *value)
3000 struct topo_node *source_node = NULL, *node;
3001 IMFTopologyNode *downstream_node;
3002 DWORD downstream_input;
3003 HRESULT hr;
3005 if (value && (value->vt != VT_UNKNOWN || !value->punkVal))
3007 WARN("Unexpected value type %d.\n", value->vt);
3008 return;
3011 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
3013 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->object.source_stream == stream)
3015 source_node = node;
3016 break;
3020 if (!source_node)
3021 return;
3023 if (!value)
3024 source_node->flags |= TOPO_NODE_END_OF_STREAM;
3026 if (FAILED(hr = IMFTopologyNode_GetOutput(source_node->node, 0, &downstream_node, &downstream_input)))
3028 WARN("Failed to get downstream node connection, hr %#x.\n", hr);
3029 return;
3032 session_deliver_sample_to_node(session, downstream_node, downstream_input, value ? (IMFSample *)value->punkVal : NULL);
3033 IMFTopologyNode_Release(downstream_node);
3036 static void session_sink_invalidated(struct media_session *session, IMFMediaEvent *event, IMFStreamSink *sink)
3038 struct topo_node *node, *sink_node = NULL;
3039 HRESULT hr;
3041 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
3043 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink)
3045 sink_node = node;
3046 break;
3050 if (!sink_node)
3051 return;
3053 if (!event)
3055 if (FAILED(hr = MFCreateMediaEvent(MESinkInvalidated, &GUID_NULL, S_OK, NULL, &event)))
3056 WARN("Failed to create event, hr %#x.\n", hr);
3059 if (!event)
3060 return;
3062 IMFMediaEvent_SetUINT64(event, &MF_EVENT_OUTPUT_NODE, sink_node->node_id);
3063 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3065 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED);
3068 static BOOL session_nodes_is_mask_set(struct media_session *session, MF_TOPOLOGY_TYPE node_type, unsigned int flags)
3070 struct media_source *source;
3071 struct topo_node *node;
3073 if (node_type == MF_TOPOLOGY_MAX)
3075 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3077 if ((source->flags & flags) != flags)
3078 return FALSE;
3081 else
3083 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
3085 if (node->type == node_type && (node->flags & flags) != flags)
3086 return FALSE;
3090 return TRUE;
3093 static void session_raise_end_of_presentation(struct media_session *session)
3095 if (!(session_nodes_is_mask_set(session, MF_TOPOLOGY_SOURCESTREAM_NODE, TOPO_NODE_END_OF_STREAM)))
3096 return;
3098 if (!(session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION))
3100 if (session_nodes_is_mask_set(session, MF_TOPOLOGY_MAX, SOURCE_FLAG_END_OF_PRESENTATION))
3102 session->presentation.flags |= SESSION_FLAG_END_OF_PRESENTATION;
3103 session_push_back_command(session, SESSION_CMD_END);
3104 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, NULL);
3109 static void session_handle_end_of_stream(struct media_session *session, IMFMediaStream *stream)
3111 struct topo_node *node;
3113 if (!(node = session_get_node_object(session, (IUnknown *)stream, MF_TOPOLOGY_SOURCESTREAM_NODE))
3114 || node->flags & TOPO_NODE_END_OF_STREAM)
3116 return;
3119 session_deliver_sample(session, stream, NULL);
3121 session_raise_end_of_presentation(session);
3124 static void session_handle_end_of_presentation(struct media_session *session, IMFMediaSource *object)
3126 struct media_source *source;
3128 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3130 if (source->source == object)
3132 if (!(source->flags & SOURCE_FLAG_END_OF_PRESENTATION))
3134 source->flags |= SOURCE_FLAG_END_OF_PRESENTATION;
3135 session_raise_end_of_presentation(session);
3138 break;
3143 static void session_sink_stream_marker(struct media_session *session, IMFStreamSink *stream_sink)
3145 struct topo_node *node;
3147 if (!(node = session_get_node_object(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE))
3148 || node->flags & TOPO_NODE_END_OF_STREAM)
3150 return;
3153 node->flags |= TOPO_NODE_END_OF_STREAM;
3155 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION &&
3156 session_nodes_is_mask_set(session, MF_TOPOLOGY_OUTPUT_NODE, TOPO_NODE_END_OF_STREAM))
3158 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED);
3159 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
3160 session_stop(session);
3164 static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
3166 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
3167 IMFMediaEventGenerator *event_source;
3168 IMFMediaEvent *event = NULL;
3169 MediaEventType event_type;
3170 IUnknown *object = NULL;
3171 IMFMediaSource *source;
3172 IMFMediaStream *stream;
3173 PROPVARIANT value;
3174 HRESULT hr;
3176 if (FAILED(hr = IMFAsyncResult_GetState(result, (IUnknown **)&event_source)))
3177 return hr;
3179 if (FAILED(hr = IMFMediaEventGenerator_EndGetEvent(event_source, result, &event)))
3181 WARN("Failed to get event from %p, hr %#x.\n", event_source, hr);
3182 goto failed;
3185 if (FAILED(hr = IMFMediaEvent_GetType(event, &event_type)))
3187 WARN("Failed to get event type, hr %#x.\n", hr);
3188 goto failed;
3191 value.vt = VT_EMPTY;
3192 if (FAILED(hr = IMFMediaEvent_GetValue(event, &value)))
3194 WARN("Failed to get event value, hr %#x.\n", hr);
3195 goto failed;
3198 switch (event_type)
3200 case MESourceStarted:
3201 case MESourcePaused:
3202 case MESourceStopped:
3203 case MEStreamStarted:
3204 case MEStreamPaused:
3205 case MEStreamStopped:
3207 EnterCriticalSection(&session->cs);
3208 session_set_source_object_state(session, (IUnknown *)event_source, event_type);
3209 LeaveCriticalSection(&session->cs);
3211 break;
3213 case MEBufferingStarted:
3214 case MEBufferingStopped:
3216 EnterCriticalSection(&session->cs);
3217 if (session_get_media_source(session, (IMFMediaSource *)event_source))
3219 if (event_type == MEBufferingStarted)
3220 IMFPresentationClock_Pause(session->clock);
3221 else
3222 IMFPresentationClock_Start(session->clock, PRESENTATION_CURRENT_POSITION);
3224 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3226 LeaveCriticalSection(&session->cs);
3227 break;
3229 case MEReconnectStart:
3230 case MEReconnectEnd:
3232 EnterCriticalSection(&session->cs);
3233 if (session_get_media_source(session, (IMFMediaSource *)event_source))
3234 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3235 LeaveCriticalSection(&session->cs);
3236 break;
3238 case MEExtendedType:
3239 case MERendererEvent:
3240 case MEStreamSinkFormatChanged:
3242 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3243 break;
3245 case MENewStream:
3246 stream = (IMFMediaStream *)value.punkVal;
3248 if (value.vt != VT_UNKNOWN || !stream)
3250 WARN("Unexpected event value.\n");
3251 break;
3254 if (FAILED(hr = IMFMediaStream_GetMediaSource(stream, &source)))
3255 break;
3257 EnterCriticalSection(&session->cs);
3258 if (SUCCEEDED(hr = session_add_media_stream(session, source, stream)))
3259 hr = IMFMediaStream_BeginGetEvent(stream, &session->events_callback, (IUnknown *)stream);
3260 LeaveCriticalSection(&session->cs);
3262 IMFMediaSource_Release(source);
3264 break;
3265 case MEStreamSinkStarted:
3266 case MEStreamSinkPaused:
3267 case MEStreamSinkStopped:
3268 case MEStreamSinkPrerolled:
3270 EnterCriticalSection(&session->cs);
3271 session_set_sink_stream_state(session, (IMFStreamSink *)event_source, event_type);
3272 LeaveCriticalSection(&session->cs);
3274 break;
3275 case MEStreamSinkMarker:
3277 EnterCriticalSection(&session->cs);
3278 session_sink_stream_marker(session, (IMFStreamSink *)event_source);
3279 LeaveCriticalSection(&session->cs);
3281 break;
3282 case MEStreamSinkRequestSample:
3284 EnterCriticalSection(&session->cs);
3285 session_request_sample(session, (IMFStreamSink *)event_source);
3286 LeaveCriticalSection(&session->cs);
3288 break;
3289 case MEMediaSample:
3291 EnterCriticalSection(&session->cs);
3292 session_deliver_sample(session, (IMFMediaStream *)event_source, &value);
3293 LeaveCriticalSection(&session->cs);
3295 break;
3296 case MEEndOfStream:
3298 EnterCriticalSection(&session->cs);
3299 session_handle_end_of_stream(session, (IMFMediaStream *)event_source);
3300 LeaveCriticalSection(&session->cs);
3302 break;
3304 case MEEndOfPresentation:
3306 EnterCriticalSection(&session->cs);
3307 session_handle_end_of_presentation(session, (IMFMediaSource *)event_source);
3308 LeaveCriticalSection(&session->cs);
3310 break;
3311 case MEAudioSessionGroupingParamChanged:
3312 case MEAudioSessionIconChanged:
3313 case MEAudioSessionNameChanged:
3314 case MEAudioSessionVolumeChanged:
3316 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3318 break;
3319 case MEAudioSessionDeviceRemoved:
3320 case MEAudioSessionDisconnected:
3321 case MEAudioSessionExclusiveModeOverride:
3322 case MEAudioSessionFormatChanged:
3323 case MEAudioSessionServerShutdown:
3325 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3326 /* fallthrough */
3327 case MESinkInvalidated:
3329 EnterCriticalSection(&session->cs);
3330 session_sink_invalidated(session, event_type == MESinkInvalidated ? event : NULL,
3331 (IMFStreamSink *)event_source);
3332 LeaveCriticalSection(&session->cs);
3334 break;
3335 case MEQualityNotify:
3337 if (session->quality_manager)
3339 if (FAILED(IMFMediaEventGenerator_QueryInterface(event_source, &IID_IMFStreamSink, (void **)&object)))
3340 IMFMediaEventGenerator_QueryInterface(event_source, &IID_IMFTransform, (void **)&object);
3342 if (object)
3344 IMFQualityManager_NotifyQualityEvent(session->quality_manager, object, event);
3345 IUnknown_Release(object);
3349 break;
3350 default:
3354 PropVariantClear(&value);
3356 failed:
3357 if (event)
3358 IMFMediaEvent_Release(event);
3360 if (FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(event_source, iface, (IUnknown *)event_source)))
3361 WARN("Failed to re-subscribe, hr %#x.\n", hr);
3363 IMFMediaEventGenerator_Release(event_source);
3365 return hr;
3368 static const IMFAsyncCallbackVtbl session_events_callback_vtbl =
3370 session_events_callback_QueryInterface,
3371 session_events_callback_AddRef,
3372 session_events_callback_Release,
3373 session_events_callback_GetParameters,
3374 session_events_callback_Invoke,
3377 static HRESULT WINAPI session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
3379 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
3380 IsEqualIID(riid, &IID_IUnknown))
3382 *obj = iface;
3383 IMFAsyncCallback_AddRef(iface);
3384 return S_OK;
3387 WARN("Unsupported %s.\n", debugstr_guid(riid));
3388 *obj = NULL;
3389 return E_NOINTERFACE;
3392 static ULONG WINAPI session_sink_finalizer_callback_AddRef(IMFAsyncCallback *iface)
3394 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3395 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3398 static ULONG WINAPI session_sink_finalizer_callback_Release(IMFAsyncCallback *iface)
3400 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3401 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3404 static HRESULT WINAPI session_sink_finalizer_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
3406 return E_NOTIMPL;
3409 static HRESULT WINAPI session_sink_finalizer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
3411 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3412 IMFFinalizableMediaSink *fin_sink = NULL;
3413 BOOL sinks_finalized = TRUE;
3414 struct media_sink *sink;
3415 IUnknown *state;
3416 HRESULT hr;
3418 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
3419 return hr;
3421 EnterCriticalSection(&session->cs);
3423 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
3425 if (state == sink->object)
3427 if (FAILED(hr = IMFMediaSink_QueryInterface(sink->sink, &IID_IMFFinalizableMediaSink, (void **)&fin_sink)))
3428 WARN("Unexpected, missing IMFFinalizableMediaSink, hr %#x.\n", hr);
3430 else
3432 sinks_finalized &= sink->finalized;
3433 if (!sinks_finalized)
3434 break;
3438 IUnknown_Release(state);
3440 if (fin_sink)
3442 /* Complete session transition, or close prematurely on error. */
3443 if (SUCCEEDED(hr = IMFFinalizableMediaSink_EndFinalize(fin_sink, result)))
3445 sink->finalized = TRUE;
3446 if (sinks_finalized)
3447 session_set_closed(session, hr);
3449 IMFFinalizableMediaSink_Release(fin_sink);
3452 LeaveCriticalSection(&session->cs);
3454 return S_OK;
3457 static const IMFAsyncCallbackVtbl session_sink_finalizer_callback_vtbl =
3459 session_sink_finalizer_callback_QueryInterface,
3460 session_sink_finalizer_callback_AddRef,
3461 session_sink_finalizer_callback_Release,
3462 session_sink_finalizer_callback_GetParameters,
3463 session_sink_finalizer_callback_Invoke,
3466 static HRESULT WINAPI session_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
3468 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3469 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
3472 static ULONG WINAPI session_rate_support_AddRef(IMFRateSupport *iface)
3474 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3475 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3478 static ULONG WINAPI session_rate_support_Release(IMFRateSupport *iface)
3480 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3481 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3484 static HRESULT session_presentation_object_get_rate(IUnknown *object, MFRATE_DIRECTION direction,
3485 BOOL thin, BOOL fastest, float *result)
3487 IMFRateSupport *rate_support;
3488 float rate;
3489 HRESULT hr;
3491 /* For objects that don't support rate control, it's assumed that only forward direction is allowed, at 1.0f. */
3493 if (FAILED(hr = MFGetService(object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support)))
3495 if (direction == MFRATE_FORWARD)
3497 *result = 1.0f;
3498 return S_OK;
3500 else
3501 return MF_E_REVERSE_UNSUPPORTED;
3504 rate = 0.0f;
3505 if (fastest)
3507 if (SUCCEEDED(hr = IMFRateSupport_GetFastestRate(rate_support, direction, thin, &rate)))
3508 *result = min(fabsf(rate), *result);
3510 else
3512 if (SUCCEEDED(hr = IMFRateSupport_GetSlowestRate(rate_support, direction, thin, &rate)))
3513 *result = max(fabsf(rate), *result);
3516 IMFRateSupport_Release(rate_support);
3518 return hr;
3521 static HRESULT session_get_presentation_rate(struct media_session *session, MFRATE_DIRECTION direction,
3522 BOOL thin, BOOL fastest, float *result)
3524 struct media_source *source;
3525 struct media_sink *sink;
3526 HRESULT hr = E_POINTER;
3527 float rate;
3529 rate = fastest ? FLT_MAX : 0.0f;
3531 EnterCriticalSection(&session->cs);
3533 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
3535 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3537 if (FAILED(hr = session_presentation_object_get_rate(source->object, direction, thin, fastest, &rate)))
3538 break;
3541 if (SUCCEEDED(hr))
3543 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
3545 if (FAILED(hr = session_presentation_object_get_rate(sink->object, direction, thin, fastest, &rate)))
3546 break;
3551 LeaveCriticalSection(&session->cs);
3553 if (SUCCEEDED(hr))
3554 *result = direction == MFRATE_FORWARD ? rate : -rate;
3556 return hr;
3559 static HRESULT session_is_presentation_rate_supported(struct media_session *session, BOOL thin, float rate,
3560 float *nearest_rate)
3562 IMFRateSupport *rate_support;
3563 struct media_source *source;
3564 struct media_sink *sink;
3565 float value = 0.0f, tmp;
3566 unsigned int flags;
3567 HRESULT hr = S_OK;
3569 if (!nearest_rate) nearest_rate = &tmp;
3571 if (rate == 0.0f)
3573 *nearest_rate = 1.0f;
3574 return S_OK;
3577 EnterCriticalSection(&session->cs);
3579 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
3581 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3583 if (FAILED(hr = MFGetService(source->object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport,
3584 (void **)&rate_support)))
3586 value = 1.0f;
3587 break;
3590 value = rate;
3591 if (FAILED(hr = IMFRateSupport_IsRateSupported(rate_support, thin, rate, &value)))
3592 WARN("Source does not support rate %f, hr %#x.\n", rate, hr);
3593 IMFRateSupport_Release(rate_support);
3595 /* Only "first" source is considered. */
3596 break;
3599 if (SUCCEEDED(hr))
3601 /* For sinks only check if rate is supported, ignoring nearest values. */
3602 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
3604 flags = 0;
3605 if (FAILED(hr = IMFMediaSink_GetCharacteristics(sink->sink, &flags)))
3606 break;
3608 if (flags & MEDIASINK_RATELESS)
3609 continue;
3611 if (FAILED(MFGetService(sink->object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport,
3612 (void **)&rate_support)))
3613 continue;
3615 hr = IMFRateSupport_IsRateSupported(rate_support, thin, rate, NULL);
3616 IMFRateSupport_Release(rate_support);
3617 if (FAILED(hr))
3619 WARN("Sink %p does not support rate %f, hr %#x.\n", sink->sink, rate, hr);
3620 break;
3626 LeaveCriticalSection(&session->cs);
3628 *nearest_rate = value;
3630 return hr;
3633 static HRESULT WINAPI session_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
3634 BOOL thin, float *rate)
3636 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3638 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
3640 return session_get_presentation_rate(session, direction, thin, FALSE, rate);
3643 static HRESULT WINAPI session_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
3644 BOOL thin, float *rate)
3646 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3648 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
3650 return session_get_presentation_rate(session, direction, thin, TRUE, rate);
3653 static HRESULT WINAPI session_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
3654 float *nearest_supported_rate)
3656 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3658 TRACE("%p, %d, %f, %p.\n", iface, thin, rate, nearest_supported_rate);
3660 return session_is_presentation_rate_supported(session, thin, rate, nearest_supported_rate);
3663 static const IMFRateSupportVtbl session_rate_support_vtbl =
3665 session_rate_support_QueryInterface,
3666 session_rate_support_AddRef,
3667 session_rate_support_Release,
3668 session_rate_support_GetSlowestRate,
3669 session_rate_support_GetFastestRate,
3670 session_rate_support_IsRateSupported,
3673 static HRESULT WINAPI session_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj)
3675 struct media_session *session = impl_session_from_IMFRateControl(iface);
3676 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
3679 static ULONG WINAPI session_rate_control_AddRef(IMFRateControl *iface)
3681 struct media_session *session = impl_session_from_IMFRateControl(iface);
3682 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3685 static ULONG WINAPI session_rate_control_Release(IMFRateControl *iface)
3687 struct media_session *session = impl_session_from_IMFRateControl(iface);
3688 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3691 static HRESULT WINAPI session_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate)
3693 FIXME("%p, %d, %f.\n", iface, thin, rate);
3695 return E_NOTIMPL;
3698 static HRESULT WINAPI session_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
3700 struct media_session *session = impl_session_from_IMFRateControl(iface);
3702 TRACE("%p, %p, %p.\n", iface, thin, rate);
3704 return IMFRateControl_GetRate(session->clock_rate_control, thin, rate);
3707 static const IMFRateControlVtbl session_rate_control_vtbl =
3709 session_rate_control_QueryInterface,
3710 session_rate_control_AddRef,
3711 session_rate_control_Release,
3712 session_rate_control_SetRate,
3713 session_rate_control_GetRate,
3716 static HRESULT WINAPI node_attribute_editor_QueryInterface(IMFTopologyNodeAttributeEditor *iface,
3717 REFIID riid, void **obj)
3719 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
3721 if (IsEqualIID(riid, &IID_IMFTopologyNodeAttributeEditor) ||
3722 IsEqualIID(riid, &IID_IUnknown))
3724 *obj = iface;
3725 IMFTopologyNodeAttributeEditor_AddRef(iface);
3726 return S_OK;
3729 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
3730 *obj = NULL;
3731 return E_NOINTERFACE;
3734 static ULONG WINAPI node_attribute_editor_AddRef(IMFTopologyNodeAttributeEditor *iface)
3736 struct media_session *session = impl_session_from_IMFTopologyNodeAttributeEditor(iface);
3737 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3740 static ULONG WINAPI node_attribute_editor_Release(IMFTopologyNodeAttributeEditor *iface)
3742 struct media_session *session = impl_session_from_IMFTopologyNodeAttributeEditor(iface);
3743 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3746 static HRESULT WINAPI node_attribute_editor_UpdateNodeAttributes(IMFTopologyNodeAttributeEditor *iface,
3747 TOPOID id, DWORD count, MFTOPONODE_ATTRIBUTE_UPDATE *updates)
3749 FIXME("%p, %s, %u, %p.\n", iface, wine_dbgstr_longlong(id), count, updates);
3751 return E_NOTIMPL;
3754 static const IMFTopologyNodeAttributeEditorVtbl node_attribute_editor_vtbl =
3756 node_attribute_editor_QueryInterface,
3757 node_attribute_editor_AddRef,
3758 node_attribute_editor_Release,
3759 node_attribute_editor_UpdateNodeAttributes,
3762 /***********************************************************************
3763 * MFCreateMediaSession (mf.@)
3765 HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **session)
3767 BOOL without_quality_manager = FALSE;
3768 struct media_session *object;
3769 HRESULT hr;
3771 TRACE("%p, %p.\n", config, session);
3773 if (!(object = calloc(1, sizeof(*object))))
3774 return E_OUTOFMEMORY;
3776 object->IMFMediaSession_iface.lpVtbl = &mfmediasessionvtbl;
3777 object->IMFGetService_iface.lpVtbl = &session_get_service_vtbl;
3778 object->IMFRateSupport_iface.lpVtbl = &session_rate_support_vtbl;
3779 object->IMFRateControl_iface.lpVtbl = &session_rate_control_vtbl;
3780 object->IMFTopologyNodeAttributeEditor_iface.lpVtbl = &node_attribute_editor_vtbl;
3781 object->commands_callback.lpVtbl = &session_commands_callback_vtbl;
3782 object->events_callback.lpVtbl = &session_events_callback_vtbl;
3783 object->sink_finalizer_callback.lpVtbl = &session_sink_finalizer_callback_vtbl;
3784 object->refcount = 1;
3785 list_init(&object->topologies);
3786 list_init(&object->commands);
3787 list_init(&object->presentation.sources);
3788 list_init(&object->presentation.sinks);
3789 list_init(&object->presentation.nodes);
3790 InitializeCriticalSection(&object->cs);
3792 if (FAILED(hr = MFCreateTopology(&object->presentation.current_topology)))
3793 goto failed;
3795 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
3796 goto failed;
3798 if (FAILED(hr = MFCreatePresentationClock(&object->clock)))
3799 goto failed;
3801 if (FAILED(hr = MFCreateSystemTimeSource(&object->system_time_source)))
3802 goto failed;
3804 if (FAILED(hr = IMFPresentationClock_QueryInterface(object->clock, &IID_IMFRateControl,
3805 (void **)&object->clock_rate_control)))
3807 goto failed;
3810 if (config)
3812 GUID clsid;
3814 if (SUCCEEDED(IMFAttributes_GetGUID(config, &MF_SESSION_TOPOLOADER, &clsid)))
3816 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTopoLoader,
3817 (void **)&object->topo_loader)))
3819 WARN("Failed to create custom topology loader, hr %#x.\n", hr);
3823 if (SUCCEEDED(IMFAttributes_GetGUID(config, &MF_SESSION_QUALITY_MANAGER, &clsid)))
3825 if (!(without_quality_manager = IsEqualGUID(&clsid, &GUID_NULL)))
3827 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFQualityManager,
3828 (void **)&object->quality_manager)))
3830 WARN("Failed to create custom quality manager, hr %#x.\n", hr);
3836 if (!object->topo_loader && FAILED(hr = MFCreateTopoLoader(&object->topo_loader)))
3837 goto failed;
3839 if (!object->quality_manager && !without_quality_manager &&
3840 FAILED(hr = MFCreateStandardQualityManager(&object->quality_manager)))
3842 goto failed;
3845 if (object->quality_manager && FAILED(hr = IMFQualityManager_NotifyPresentationClock(object->quality_manager,
3846 object->clock)))
3848 goto failed;
3851 *session = &object->IMFMediaSession_iface;
3853 return S_OK;
3855 failed:
3856 IMFMediaSession_Release(&object->IMFMediaSession_iface);
3857 return hr;
3860 static HRESULT WINAPI standard_quality_manager_QueryInterface(IMFQualityManager *iface, REFIID riid, void **out)
3862 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3864 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
3866 if (IsEqualIID(riid, &IID_IMFQualityManager) ||
3867 IsEqualIID(riid, &IID_IUnknown))
3869 *out = iface;
3871 else if (IsEqualIID(riid, &IID_IMFClockStateSink))
3873 *out = &manager->IMFClockStateSink_iface;
3875 else
3877 WARN("Unsupported %s.\n", debugstr_guid(riid));
3878 *out = NULL;
3879 return E_NOINTERFACE;
3882 IUnknown_AddRef((IUnknown *)*out);
3883 return S_OK;
3886 static ULONG WINAPI standard_quality_manager_AddRef(IMFQualityManager *iface)
3888 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3889 ULONG refcount = InterlockedIncrement(&manager->refcount);
3891 TRACE("%p, refcount %u.\n", iface, refcount);
3893 return refcount;
3896 static ULONG WINAPI standard_quality_manager_Release(IMFQualityManager *iface)
3898 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3899 ULONG refcount = InterlockedDecrement(&manager->refcount);
3901 TRACE("%p, refcount %u.\n", iface, refcount);
3903 if (!refcount)
3905 if (manager->clock)
3906 IMFPresentationClock_Release(manager->clock);
3907 if (manager->topology)
3908 IMFTopology_Release(manager->topology);
3909 DeleteCriticalSection(&manager->cs);
3910 free(manager);
3913 return refcount;
3916 static void standard_quality_manager_set_topology(struct quality_manager *manager, IMFTopology *topology)
3918 if (manager->topology)
3919 IMFTopology_Release(manager->topology);
3920 manager->topology = topology;
3921 if (manager->topology)
3922 IMFTopology_AddRef(manager->topology);
3925 static HRESULT WINAPI standard_quality_manager_NotifyTopology(IMFQualityManager *iface, IMFTopology *topology)
3927 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3928 HRESULT hr = S_OK;
3930 TRACE("%p, %p.\n", iface, topology);
3932 EnterCriticalSection(&manager->cs);
3933 if (manager->state == QUALITY_MANAGER_SHUT_DOWN)
3934 hr = MF_E_SHUTDOWN;
3935 else
3937 standard_quality_manager_set_topology(manager, topology);
3939 LeaveCriticalSection(&manager->cs);
3941 return hr;
3944 static void standard_quality_manager_release_clock(struct quality_manager *manager)
3946 if (manager->clock)
3948 IMFPresentationClock_RemoveClockStateSink(manager->clock, &manager->IMFClockStateSink_iface);
3949 IMFPresentationClock_Release(manager->clock);
3951 manager->clock = NULL;
3954 static HRESULT WINAPI standard_quality_manager_NotifyPresentationClock(IMFQualityManager *iface,
3955 IMFPresentationClock *clock)
3957 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
3958 HRESULT hr = S_OK;
3960 TRACE("%p, %p.\n", iface, clock);
3962 EnterCriticalSection(&manager->cs);
3963 if (manager->state == QUALITY_MANAGER_SHUT_DOWN)
3964 hr = MF_E_SHUTDOWN;
3965 else if (!clock)
3966 hr = E_POINTER;
3967 else
3969 standard_quality_manager_release_clock(manager);
3970 manager->clock = clock;
3971 IMFPresentationClock_AddRef(manager->clock);
3972 if (FAILED(IMFPresentationClock_AddClockStateSink(manager->clock, &manager->IMFClockStateSink_iface)))
3973 WARN("Failed to set state sink.\n");
3975 LeaveCriticalSection(&manager->cs);
3977 return hr;
3980 static HRESULT WINAPI standard_quality_manager_NotifyProcessInput(IMFQualityManager *iface, IMFTopologyNode *node,
3981 LONG input_index, IMFSample *sample)
3983 TRACE("%p, %p, %d, %p stub.\n", iface, node, input_index, sample);
3985 return E_NOTIMPL;
3988 static HRESULT WINAPI standard_quality_manager_NotifyProcessOutput(IMFQualityManager *iface, IMFTopologyNode *node,
3989 LONG output_index, IMFSample *sample)
3991 TRACE("%p, %p, %d, %p stub.\n", iface, node, output_index, sample);
3993 return E_NOTIMPL;
3996 static HRESULT WINAPI standard_quality_manager_NotifyQualityEvent(IMFQualityManager *iface, IUnknown *object,
3997 IMFMediaEvent *event)
3999 FIXME("%p, %p, %p stub.\n", iface, object, event);
4001 return E_NOTIMPL;
4004 static HRESULT WINAPI standard_quality_manager_Shutdown(IMFQualityManager *iface)
4006 struct quality_manager *manager = impl_from_IMFQualityManager(iface);
4008 TRACE("%p.\n", iface);
4010 EnterCriticalSection(&manager->cs);
4011 if (manager->state != QUALITY_MANAGER_SHUT_DOWN)
4013 standard_quality_manager_release_clock(manager);
4014 standard_quality_manager_set_topology(manager, NULL);
4015 manager->state = QUALITY_MANAGER_SHUT_DOWN;
4017 LeaveCriticalSection(&manager->cs);
4019 return S_OK;
4022 static const IMFQualityManagerVtbl standard_quality_manager_vtbl =
4024 standard_quality_manager_QueryInterface,
4025 standard_quality_manager_AddRef,
4026 standard_quality_manager_Release,
4027 standard_quality_manager_NotifyTopology,
4028 standard_quality_manager_NotifyPresentationClock,
4029 standard_quality_manager_NotifyProcessInput,
4030 standard_quality_manager_NotifyProcessOutput,
4031 standard_quality_manager_NotifyQualityEvent,
4032 standard_quality_manager_Shutdown,
4035 static HRESULT WINAPI standard_quality_manager_sink_QueryInterface(IMFClockStateSink *iface,
4036 REFIID riid, void **obj)
4038 struct quality_manager *manager = impl_from_qm_IMFClockStateSink(iface);
4039 return IMFQualityManager_QueryInterface(&manager->IMFQualityManager_iface, riid, obj);
4042 static ULONG WINAPI standard_quality_manager_sink_AddRef(IMFClockStateSink *iface)
4044 struct quality_manager *manager = impl_from_qm_IMFClockStateSink(iface);
4045 return IMFQualityManager_AddRef(&manager->IMFQualityManager_iface);
4048 static ULONG WINAPI standard_quality_manager_sink_Release(IMFClockStateSink *iface)
4050 struct quality_manager *manager = impl_from_qm_IMFClockStateSink(iface);
4051 return IMFQualityManager_Release(&manager->IMFQualityManager_iface);
4054 static HRESULT WINAPI standard_quality_manager_sink_OnClockStart(IMFClockStateSink *iface,
4055 MFTIME systime, LONGLONG offset)
4057 return S_OK;
4060 static HRESULT WINAPI standard_quality_manager_sink_OnClockStop(IMFClockStateSink *iface,
4061 MFTIME systime)
4063 return S_OK;
4066 static HRESULT WINAPI standard_quality_manager_sink_OnClockPause(IMFClockStateSink *iface,
4067 MFTIME systime)
4069 return S_OK;
4072 static HRESULT WINAPI standard_quality_manager_sink_OnClockRestart(IMFClockStateSink *iface,
4073 MFTIME systime)
4075 return S_OK;
4078 static HRESULT WINAPI standard_quality_manager_sink_OnClockSetRate(IMFClockStateSink *iface,
4079 MFTIME systime, float rate)
4081 return S_OK;
4084 static const IMFClockStateSinkVtbl standard_quality_manager_sink_vtbl =
4086 standard_quality_manager_sink_QueryInterface,
4087 standard_quality_manager_sink_AddRef,
4088 standard_quality_manager_sink_Release,
4089 standard_quality_manager_sink_OnClockStart,
4090 standard_quality_manager_sink_OnClockStop,
4091 standard_quality_manager_sink_OnClockPause,
4092 standard_quality_manager_sink_OnClockRestart,
4093 standard_quality_manager_sink_OnClockSetRate,
4096 HRESULT WINAPI MFCreateStandardQualityManager(IMFQualityManager **manager)
4098 struct quality_manager *object;
4100 TRACE("%p.\n", manager);
4102 if (!(object = calloc(1, sizeof(*object))))
4103 return E_OUTOFMEMORY;
4105 object->IMFQualityManager_iface.lpVtbl = &standard_quality_manager_vtbl;
4106 object->IMFClockStateSink_iface.lpVtbl = &standard_quality_manager_sink_vtbl;
4107 object->refcount = 1;
4108 InitializeCriticalSection(&object->cs);
4110 *manager = &object->IMFQualityManager_iface;
4112 return S_OK;