d3d10: Return the read value from read_dword().
[wine.git] / dlls / mf / session.c
blobe6c21332d200b179cf4d6e733709bd0bcb423706
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 DWORD 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 DWORD *input_map;
201 unsigned int input_count;
203 struct transform_stream *outputs;
204 DWORD *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 static inline struct media_session *impl_from_IMFMediaSession(IMFMediaSession *iface)
259 return CONTAINING_RECORD(iface, struct media_session, IMFMediaSession_iface);
262 static struct media_session *impl_from_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
264 return CONTAINING_RECORD(iface, struct media_session, commands_callback);
267 static struct media_session *impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
269 return CONTAINING_RECORD(iface, struct media_session, events_callback);
272 static struct media_session *impl_from_sink_finalizer_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
274 return CONTAINING_RECORD(iface, struct media_session, sink_finalizer_callback);
277 static struct media_session *impl_from_IMFGetService(IMFGetService *iface)
279 return CONTAINING_RECORD(iface, struct media_session, IMFGetService_iface);
282 static struct media_session *impl_session_from_IMFRateSupport(IMFRateSupport *iface)
284 return CONTAINING_RECORD(iface, struct media_session, IMFRateSupport_iface);
287 static struct media_session *impl_session_from_IMFRateControl(IMFRateControl *iface)
289 return CONTAINING_RECORD(iface, struct media_session, IMFRateControl_iface);
292 static struct media_session *impl_session_from_IMFTopologyNodeAttributeEditor(IMFTopologyNodeAttributeEditor *iface)
294 return CONTAINING_RECORD(iface, struct media_session, IMFTopologyNodeAttributeEditor_iface);
297 static struct session_op *impl_op_from_IUnknown(IUnknown *iface)
299 return CONTAINING_RECORD(iface, struct session_op, IUnknown_iface);
302 static struct topo_node *impl_node_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify *iface)
304 return CONTAINING_RECORD(iface, struct topo_node, u.sink.notify_cb);
307 /* IMFLocalMFTRegistration */
308 static HRESULT WINAPI local_mft_registration_QueryInterface(IMFLocalMFTRegistration *iface, REFIID riid, void **obj)
310 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
312 if (IsEqualIID(riid, &IID_IMFLocalMFTRegistration) ||
313 IsEqualIID(riid, &IID_IUnknown))
315 *obj = iface;
316 IMFLocalMFTRegistration_AddRef(iface);
317 return S_OK;
320 WARN("Unexpected %s.\n", debugstr_guid(riid));
321 *obj = NULL;
322 return E_NOINTERFACE;
325 static ULONG WINAPI local_mft_registration_AddRef(IMFLocalMFTRegistration *iface)
327 return 2;
330 static ULONG WINAPI local_mft_registration_Release(IMFLocalMFTRegistration *iface)
332 return 1;
335 static HRESULT WINAPI local_mft_registration_RegisterMFTs(IMFLocalMFTRegistration *iface, MFT_REGISTRATION_INFO *info,
336 DWORD count)
338 HRESULT hr = S_OK;
339 DWORD i;
341 TRACE("%p, %p, %u.\n", iface, info, count);
343 for (i = 0; i < count; ++i)
345 if (FAILED(hr = MFTRegisterLocalByCLSID(&info[i].clsid, &info[i].guidCategory, info[i].pszName,
346 info[i].uiFlags, info[i].cInTypes, info[i].pInTypes, info[i].cOutTypes, info[i].pOutTypes)))
348 break;
352 return hr;
355 static const IMFLocalMFTRegistrationVtbl local_mft_registration_vtbl =
357 local_mft_registration_QueryInterface,
358 local_mft_registration_AddRef,
359 local_mft_registration_Release,
360 local_mft_registration_RegisterMFTs,
363 static IMFLocalMFTRegistration local_mft_registration = { &local_mft_registration_vtbl };
365 static HRESULT WINAPI session_op_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
367 if (IsEqualIID(riid, &IID_IUnknown))
369 *obj = iface;
370 IUnknown_AddRef(iface);
371 return S_OK;
374 *obj = NULL;
375 return E_NOINTERFACE;
378 static ULONG WINAPI session_op_AddRef(IUnknown *iface)
380 struct session_op *op = impl_op_from_IUnknown(iface);
381 ULONG refcount = InterlockedIncrement(&op->refcount);
383 TRACE("%p, refcount %u.\n", iface, refcount);
385 return refcount;
388 static ULONG WINAPI session_op_Release(IUnknown *iface)
390 struct session_op *op = impl_op_from_IUnknown(iface);
391 ULONG refcount = InterlockedDecrement(&op->refcount);
393 TRACE("%p, refcount %u.\n", iface, refcount);
395 if (!refcount)
397 switch (op->command)
399 case SESSION_CMD_SET_TOPOLOGY:
400 if (op->u.set_topology.topology)
401 IMFTopology_Release(op->u.set_topology.topology);
402 break;
403 case SESSION_CMD_START:
404 PropVariantClear(&op->u.start.start_position);
405 break;
406 case SESSION_CMD_QM_NOTIFY_TOPOLOGY:
407 if (op->u.notify_topology.topology)
408 IMFTopology_Release(op->u.notify_topology.topology);
409 break;
410 default:
413 free(op);
416 return refcount;
419 static const IUnknownVtbl session_op_vtbl =
421 session_op_QueryInterface,
422 session_op_AddRef,
423 session_op_Release,
426 static HRESULT create_session_op(enum session_command command, struct session_op **ret)
428 struct session_op *op;
430 if (!(op = calloc(1, sizeof(*op))))
431 return E_OUTOFMEMORY;
433 op->IUnknown_iface.lpVtbl = &session_op_vtbl;
434 op->refcount = 1;
435 op->command = command;
437 *ret = op;
439 return S_OK;
442 static HRESULT session_is_shut_down(struct media_session *session)
444 return session->state == SESSION_STATE_SHUT_DOWN ? MF_E_SHUTDOWN : S_OK;
447 static void session_push_back_command(struct media_session *session, enum session_command command)
449 struct session_op *op;
451 if (SUCCEEDED(create_session_op(command, &op)))
452 list_add_head(&session->commands, &op->entry);
455 static HRESULT session_submit_command(struct media_session *session, struct session_op *op)
457 HRESULT hr;
459 EnterCriticalSection(&session->cs);
460 if (SUCCEEDED(hr = session_is_shut_down(session)))
462 if (list_empty(&session->commands))
463 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface);
464 list_add_tail(&session->commands, &op->entry);
465 IUnknown_AddRef(&op->IUnknown_iface);
467 LeaveCriticalSection(&session->cs);
469 return hr;
472 static HRESULT session_submit_simple_command(struct media_session *session, enum session_command command)
474 struct session_op *op;
475 HRESULT hr;
477 if (FAILED(hr = create_session_op(command, &op)))
478 return hr;
480 hr = session_submit_command(session, op);
481 IUnknown_Release(&op->IUnknown_iface);
482 return hr;
485 static void session_clear_queued_topologies(struct media_session *session)
487 struct queued_topology *ptr, *next;
489 LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &session->topologies, struct queued_topology, entry)
491 list_remove(&ptr->entry);
492 IMFTopology_Release(ptr->topology);
493 free(ptr);
497 static void session_set_topo_status(struct media_session *session, HRESULT status,
498 MF_TOPOSTATUS topo_status)
500 IMFMediaEvent *event;
501 PROPVARIANT param;
503 if (topo_status == MF_TOPOSTATUS_INVALID)
504 return;
506 if (list_empty(&session->topologies))
508 FIXME("Unexpectedly empty topology queue.\n");
509 return;
512 if (topo_status > session->presentation.topo_status)
514 struct queued_topology *topology = LIST_ENTRY(list_head(&session->topologies), struct queued_topology, entry);
516 param.vt = VT_UNKNOWN;
517 param.punkVal = (IUnknown *)topology->topology;
519 if (FAILED(MFCreateMediaEvent(MESessionTopologyStatus, &GUID_NULL, status, &param, &event)))
520 return;
522 session->presentation.topo_status = topo_status;
524 IMFMediaEvent_SetUINT32(event, &MF_EVENT_TOPOLOGY_STATUS, topo_status);
525 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
526 IMFMediaEvent_Release(event);
530 static HRESULT session_bind_output_nodes(IMFTopology *topology)
532 MF_TOPOLOGY_TYPE node_type;
533 IMFStreamSink *stream_sink;
534 IMFMediaSink *media_sink;
535 WORD node_count = 0, i;
536 IMFTopologyNode *node;
537 IMFActivate *activate;
538 UINT32 stream_id;
539 IUnknown *object;
540 HRESULT hr;
542 hr = IMFTopology_GetNodeCount(topology, &node_count);
544 for (i = 0; i < node_count; ++i)
546 if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
547 break;
549 if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type)) || node_type != MF_TOPOLOGY_OUTPUT_NODE)
551 IMFTopologyNode_Release(node);
552 continue;
555 if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object)))
557 stream_sink = NULL;
558 if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&stream_sink)))
560 if (SUCCEEDED(hr = IUnknown_QueryInterface(object, &IID_IMFActivate, (void **)&activate)))
562 if (SUCCEEDED(hr = IMFActivate_ActivateObject(activate, &IID_IMFMediaSink, (void **)&media_sink)))
564 if (FAILED(IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_STREAMID, &stream_id)))
565 stream_id = 0;
567 stream_sink = NULL;
568 if (FAILED(IMFMediaSink_GetStreamSinkById(media_sink, stream_id, &stream_sink)))
569 hr = IMFMediaSink_AddStreamSink(media_sink, stream_id, NULL, &stream_sink);
571 if (stream_sink)
572 hr = IMFTopologyNode_SetObject(node, (IUnknown *)stream_sink);
574 IMFMediaSink_Release(media_sink);
577 if (SUCCEEDED(hr))
578 IMFTopologyNode_SetUnknown(node, &_MF_TOPONODE_IMFActivate, (IUnknown *)activate);
580 IMFActivate_Release(activate);
584 if (stream_sink)
585 IMFStreamSink_Release(stream_sink);
586 IUnknown_Release(object);
589 IMFTopologyNode_Release(node);
592 return hr;
595 static void session_set_caps(struct media_session *session, DWORD caps)
597 DWORD delta = session->caps ^ caps;
598 IMFMediaEvent *event;
600 /* Delta is documented to reflect rate value changes as well, but it's not clear what to compare
601 them to, since session always queries for current object rates. */
602 if (!delta)
603 return;
605 session->caps = caps;
607 if (FAILED(MFCreateMediaEvent(MESessionCapabilitiesChanged, &GUID_NULL, S_OK, NULL, &event)))
608 return;
610 IMFMediaEvent_SetUINT32(event, &MF_EVENT_SESSIONCAPS, caps);
611 IMFMediaEvent_SetUINT32(event, &MF_EVENT_SESSIONCAPS_DELTA, delta);
613 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
614 IMFMediaEvent_Release(event);
617 static void transform_release_sample(struct sample *sample)
619 list_remove(&sample->entry);
620 if (sample->sample)
621 IMFSample_Release(sample->sample);
622 free(sample);
625 static void transform_stream_drop_samples(struct transform_stream *stream)
627 struct sample *sample, *sample2;
629 LIST_FOR_EACH_ENTRY_SAFE(sample, sample2, &stream->samples, struct sample, entry)
630 transform_release_sample(sample);
633 static void release_topo_node(struct topo_node *node)
635 unsigned int i;
637 switch (node->type)
639 case MF_TOPOLOGY_SOURCESTREAM_NODE:
640 if (node->u.source.source)
641 IMFMediaSource_Release(node->u.source.source);
642 break;
643 case MF_TOPOLOGY_TRANSFORM_NODE:
644 for (i = 0; i < node->u.transform.input_count; ++i)
645 transform_stream_drop_samples(&node->u.transform.inputs[i]);
646 for (i = 0; i < node->u.transform.output_count; ++i)
647 transform_stream_drop_samples(&node->u.transform.outputs[i]);
648 free(node->u.transform.inputs);
649 free(node->u.transform.outputs);
650 free(node->u.transform.input_map);
651 free(node->u.transform.output_map);
652 break;
653 case MF_TOPOLOGY_OUTPUT_NODE:
654 if (node->u.sink.allocator)
655 IMFVideoSampleAllocator_Release(node->u.sink.allocator);
656 if (node->u.sink.allocator_cb)
658 IMFVideoSampleAllocatorCallback_SetCallback(node->u.sink.allocator_cb, NULL);
659 IMFVideoSampleAllocatorCallback_Release(node->u.sink.allocator_cb);
661 break;
662 default:
666 if (node->object.object)
667 IUnknown_Release(node->object.object);
668 if (node->node)
669 IMFTopologyNode_Release(node->node);
670 free(node);
673 static void session_shutdown_current_topology(struct media_session *session)
675 unsigned int shutdown, force_shutdown;
676 MF_TOPOLOGY_TYPE node_type;
677 IMFStreamSink *stream_sink;
678 IMFTopology *topology;
679 IMFTopologyNode *node;
680 IMFActivate *activate;
681 IMFMediaSink *sink;
682 WORD idx = 0;
683 HRESULT hr;
685 topology = session->presentation.current_topology;
686 force_shutdown = session->state == SESSION_STATE_SHUT_DOWN;
688 /* FIXME: should handle async MFTs, but these are not supported by the rest of the pipeline currently. */
690 while (SUCCEEDED(IMFTopology_GetNode(topology, idx++, &node)))
692 if (SUCCEEDED(IMFTopologyNode_GetNodeType(node, &node_type)) &&
693 node_type == MF_TOPOLOGY_OUTPUT_NODE)
695 shutdown = 1;
696 IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, &shutdown);
698 if (force_shutdown || shutdown)
700 if (SUCCEEDED(IMFTopologyNode_GetUnknown(node, &_MF_TOPONODE_IMFActivate, &IID_IMFActivate,
701 (void **)&activate)))
703 if (FAILED(hr = IMFActivate_ShutdownObject(activate)))
704 WARN("Failed to shut down activation object for the sink, hr %#x.\n", hr);
705 IMFActivate_Release(activate);
707 else if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink)))
709 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink)))
711 IMFMediaSink_Shutdown(sink);
712 IMFMediaSink_Release(sink);
715 IMFStreamSink_Release(stream_sink);
720 IMFTopologyNode_Release(node);
724 static void session_clear_command_list(struct media_session *session)
726 struct session_op *op, *op2;
728 LIST_FOR_EACH_ENTRY_SAFE(op, op2, &session->commands, struct session_op, entry)
730 list_remove(&op->entry);
731 IUnknown_Release(&op->IUnknown_iface);
735 static void session_clear_presentation(struct media_session *session)
737 struct media_source *source, *source2;
738 struct media_sink *sink, *sink2;
739 struct topo_node *node, *node2;
741 session_shutdown_current_topology(session);
743 IMFTopology_Clear(session->presentation.current_topology);
744 session->presentation.topo_status = MF_TOPOSTATUS_INVALID;
746 LIST_FOR_EACH_ENTRY_SAFE(source, source2, &session->presentation.sources, struct media_source, entry)
748 list_remove(&source->entry);
749 if (source->source)
750 IMFMediaSource_Release(source->source);
751 if (source->pd)
752 IMFPresentationDescriptor_Release(source->pd);
753 free(source);
756 LIST_FOR_EACH_ENTRY_SAFE(node, node2, &session->presentation.nodes, struct topo_node, entry)
758 list_remove(&node->entry);
759 release_topo_node(node);
762 LIST_FOR_EACH_ENTRY_SAFE(sink, sink2, &session->presentation.sinks, struct media_sink, entry)
764 list_remove(&sink->entry);
766 if (sink->sink)
767 IMFMediaSink_Release(sink->sink);
768 if (sink->preroll)
769 IMFMediaSinkPreroll_Release(sink->preroll);
770 if (sink->event_generator)
771 IMFMediaEventGenerator_Release(sink->event_generator);
772 free(sink);
776 static struct topo_node *session_get_node_by_id(const struct media_session *session, TOPOID id)
778 struct topo_node *node;
780 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
782 if (node->node_id == id)
783 return node;
786 return NULL;
789 static void session_command_complete(struct media_session *session)
791 struct session_op *op;
792 struct list *e;
794 /* Pop current command, submit next. */
795 if ((e = list_head(&session->commands)))
797 op = LIST_ENTRY(e, struct session_op, entry);
798 list_remove(&op->entry);
799 IUnknown_Release(&op->IUnknown_iface);
802 if ((e = list_head(&session->commands)))
804 op = LIST_ENTRY(e, struct session_op, entry);
805 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface);
809 static void session_command_complete_with_event(struct media_session *session, MediaEventType event,
810 HRESULT status, const PROPVARIANT *param)
812 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, event, &GUID_NULL, status, param);
813 session_command_complete(session);
816 static void session_start(struct media_session *session, const GUID *time_format, const PROPVARIANT *start_position)
818 struct media_source *source;
819 HRESULT hr;
821 switch (session->state)
823 case SESSION_STATE_STOPPED:
825 /* Start request with no current topology. */
826 if (session->presentation.topo_status == MF_TOPOSTATUS_INVALID)
828 session_command_complete_with_event(session, MESessionStarted, MF_E_INVALIDREQUEST, NULL);
829 break;
832 /* fallthrough */
833 case SESSION_STATE_PAUSED:
835 session->presentation.time_format = *time_format;
836 session->presentation.start_position.vt = VT_EMPTY;
837 PropVariantCopy(&session->presentation.start_position, start_position);
839 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
841 if (!(session->presentation.flags & SESSION_FLAG_SOURCES_SUBSCRIBED))
843 if (FAILED(hr = IMFMediaSource_BeginGetEvent(source->source, &session->events_callback,
844 source->object)))
846 WARN("Failed to subscribe to source events, hr %#x.\n", hr);
850 if (FAILED(hr = IMFMediaSource_Start(source->source, source->pd, &GUID_NULL, start_position)))
851 WARN("Failed to start media source %p, hr %#x.\n", source->source, hr);
854 session->presentation.flags |= SESSION_FLAG_SOURCES_SUBSCRIBED;
855 session->state = SESSION_STATE_STARTING_SOURCES;
856 break;
857 case SESSION_STATE_STARTED:
858 FIXME("Seeking is not implemented.\n");
859 session_command_complete(session);
860 break;
861 default:
862 session_command_complete_with_event(session, MESessionStarted, MF_E_INVALIDREQUEST, NULL);
863 break;
867 static void session_set_started(struct media_session *session)
869 struct media_source *source;
870 IMFMediaEvent *event;
871 unsigned int caps;
872 DWORD flags;
874 session->state = SESSION_STATE_STARTED;
876 caps = session->caps | MFSESSIONCAP_PAUSE;
878 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
880 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source->source, &flags)))
882 if (!(flags & MFMEDIASOURCE_CAN_PAUSE))
884 caps &= ~MFSESSIONCAP_PAUSE;
885 break;
890 session_set_caps(session, caps);
892 if (SUCCEEDED(MFCreateMediaEvent(MESessionStarted, &GUID_NULL, S_OK, NULL, &event)))
894 IMFMediaEvent_SetUINT64(event, &MF_EVENT_PRESENTATION_TIME_OFFSET, 0);
895 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
896 IMFMediaEvent_Release(event);
898 session_command_complete(session);
901 static void session_set_paused(struct media_session *session, unsigned int state, HRESULT status)
903 /* Failed event status could indicate a failure during normal transition to paused state,
904 or an attempt to pause from invalid initial state. To finalize failed transition in the former case,
905 state is still forced to PAUSED, otherwise previous state is retained. */
906 if (state != ~0u) session->state = state;
907 if (SUCCEEDED(status))
908 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
909 session_command_complete_with_event(session, MESessionPaused, status, NULL);
912 static void session_set_closed(struct media_session *session, HRESULT status)
914 session->state = SESSION_STATE_CLOSED;
915 if (SUCCEEDED(status))
916 session_set_caps(session, session->caps & ~(MFSESSIONCAP_START | MFSESSIONCAP_SEEK));
917 session_command_complete_with_event(session, MESessionClosed, status, NULL);
920 static void session_pause(struct media_session *session)
922 unsigned int state = ~0u;
923 HRESULT hr;
925 switch (session->state)
927 case SESSION_STATE_STARTED:
929 /* Transition in two steps - pause the clock, wait for sinks, then pause sources. */
930 if (SUCCEEDED(hr = IMFPresentationClock_Pause(session->clock)))
931 session->state = SESSION_STATE_PAUSING_SINKS;
932 state = SESSION_STATE_PAUSED;
934 break;
936 case SESSION_STATE_STOPPED:
937 hr = MF_E_SESSION_PAUSEWHILESTOPPED;
938 break;
939 default:
940 hr = MF_E_INVALIDREQUEST;
943 if (FAILED(hr))
944 session_set_paused(session, state, hr);
947 static void session_clear_end_of_presentation(struct media_session *session)
949 struct media_source *source;
950 struct topo_node *node;
952 session->presentation.flags &= ~SESSION_FLAG_END_OF_PRESENTATION;
953 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
955 source->flags &= ~SOURCE_FLAG_END_OF_PRESENTATION;
957 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
959 node->flags &= ~TOPO_NODE_END_OF_STREAM;
961 session->presentation.topo_status = MF_TOPOSTATUS_READY;
964 static void session_set_stopped(struct media_session *session, HRESULT status)
966 MediaEventType event_type;
967 IMFMediaEvent *event;
969 session->state = SESSION_STATE_STOPPED;
970 event_type = session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION ? MESessionEnded : MESessionStopped;
972 if (SUCCEEDED(MFCreateMediaEvent(event_type, &GUID_NULL, status, NULL, &event)))
974 IMFMediaEvent_SetUINT64(event, &MF_SESSION_APPROX_EVENT_OCCURRENCE_TIME, session->presentation.clock_stop_time);
975 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
976 IMFMediaEvent_Release(event);
978 session_clear_end_of_presentation(session);
979 session_command_complete(session);
982 static void session_stop(struct media_session *session)
984 HRESULT hr = MF_E_INVALIDREQUEST;
986 switch (session->state)
988 case SESSION_STATE_STARTED:
989 case SESSION_STATE_PAUSED:
991 /* Transition in two steps - stop the clock, wait for sinks, then stop sources. */
992 IMFPresentationClock_GetTime(session->clock, &session->presentation.clock_stop_time);
993 if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock)))
994 session->state = SESSION_STATE_STOPPING_SINKS;
995 else
996 session_set_stopped(session, hr);
998 break;
999 case SESSION_STATE_STOPPED:
1000 hr = S_OK;
1001 /* fallthrough */
1002 default:
1003 session_command_complete_with_event(session, MESessionStopped, hr, NULL);
1004 break;
1008 static HRESULT session_finalize_sinks(struct media_session *session)
1010 IMFFinalizableMediaSink *fin_sink;
1011 BOOL sinks_finalized = TRUE;
1012 struct media_sink *sink;
1013 HRESULT hr = S_OK;
1015 session->presentation.flags &= ~SESSION_FLAG_FINALIZE_SINKS;
1016 session->state = SESSION_STATE_FINALIZING_SINKS;
1018 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
1020 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink->sink, &IID_IMFFinalizableMediaSink, (void **)&fin_sink)))
1022 hr = IMFFinalizableMediaSink_BeginFinalize(fin_sink, &session->sink_finalizer_callback,
1023 (IUnknown *)fin_sink);
1024 IMFFinalizableMediaSink_Release(fin_sink);
1025 if (FAILED(hr))
1026 break;
1027 sinks_finalized = FALSE;
1029 else
1030 sink->finalized = TRUE;
1033 if (sinks_finalized)
1034 session_set_closed(session, hr);
1036 return hr;
1039 static void session_close(struct media_session *session)
1041 HRESULT hr = S_OK;
1043 switch (session->state)
1045 case SESSION_STATE_STOPPED:
1046 hr = session_finalize_sinks(session);
1047 break;
1048 case SESSION_STATE_STARTED:
1049 case SESSION_STATE_PAUSED:
1050 session->presentation.flags |= SESSION_FLAG_FINALIZE_SINKS;
1051 if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock)))
1052 session->state = SESSION_STATE_STOPPING_SINKS;
1053 break;
1054 default:
1055 hr = MF_E_INVALIDREQUEST;
1056 break;
1059 session_clear_queued_topologies(session);
1060 if (FAILED(hr))
1061 session_set_closed(session, hr);
1064 static void session_clear_topologies(struct media_session *session)
1066 HRESULT hr = S_OK;
1068 if (session->state == SESSION_STATE_CLOSED)
1069 hr = MF_E_INVALIDREQUEST;
1070 else
1071 session_clear_queued_topologies(session);
1072 session_command_complete_with_event(session, MESessionTopologiesCleared, hr, NULL);
1075 static struct media_source *session_get_media_source(struct media_session *session, IMFMediaSource *source)
1077 struct media_source *cur;
1079 LIST_FOR_EACH_ENTRY(cur, &session->presentation.sources, struct media_source, entry)
1081 if (source == cur->source)
1082 return cur;
1085 return NULL;
1088 static void session_release_media_source(struct media_source *source)
1090 IMFMediaSource_Release(source->source);
1091 if (source->pd)
1092 IMFPresentationDescriptor_Release(source->pd);
1093 free(source);
1096 static HRESULT session_add_media_source(struct media_session *session, IMFTopologyNode *node, IMFMediaSource *source)
1098 struct media_source *media_source;
1099 HRESULT hr;
1101 if (session_get_media_source(session, source))
1102 return S_FALSE;
1104 if (!(media_source = calloc(1, sizeof(*media_source))))
1105 return E_OUTOFMEMORY;
1107 media_source->source = source;
1108 IMFMediaSource_AddRef(media_source->source);
1110 hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, &IID_IMFPresentationDescriptor,
1111 (void **)&media_source->pd);
1113 if (SUCCEEDED(hr))
1114 list_add_tail(&session->presentation.sources, &media_source->entry);
1115 else
1116 session_release_media_source(media_source);
1118 return hr;
1121 static void session_raise_topology_set(struct media_session *session, IMFTopology *topology, HRESULT status)
1123 PROPVARIANT param;
1125 param.vt = topology ? VT_UNKNOWN : VT_EMPTY;
1126 param.punkVal = (IUnknown *)topology;
1128 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologySet, &GUID_NULL, status, &param);
1131 static DWORD session_get_object_rate_caps(IUnknown *object)
1133 IMFRateSupport *rate_support;
1134 DWORD caps = 0;
1135 float rate;
1137 if (SUCCEEDED(MFGetService(object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support)))
1139 rate = 0.0f;
1140 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support, MFRATE_FORWARD, TRUE, &rate)) && rate != 0.0f)
1141 caps |= MFSESSIONCAP_RATE_FORWARD;
1143 rate = 0.0f;
1144 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support, MFRATE_REVERSE, TRUE, &rate)) && rate != 0.0f)
1145 caps |= MFSESSIONCAP_RATE_REVERSE;
1147 IMFRateSupport_Release(rate_support);
1150 return caps;
1153 static HRESULT session_add_media_sink(struct media_session *session, IMFTopologyNode *node, IMFMediaSink *sink)
1155 struct media_sink *media_sink;
1156 unsigned int disable_preroll = 0;
1157 DWORD flags;
1159 LIST_FOR_EACH_ENTRY(media_sink, &session->presentation.sinks, struct media_sink, entry)
1161 if (sink == media_sink->sink)
1162 return S_FALSE;
1165 if (!(media_sink = calloc(1, sizeof(*media_sink))))
1166 return E_OUTOFMEMORY;
1168 media_sink->sink = sink;
1169 IMFMediaSink_AddRef(media_sink->sink);
1171 IMFMediaSink_QueryInterface(media_sink->sink, &IID_IMFMediaEventGenerator, (void **)&media_sink->event_generator);
1173 IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_DISABLE_PREROLL, &disable_preroll);
1174 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink, &flags)) && flags & MEDIASINK_CAN_PREROLL && !disable_preroll)
1176 if (SUCCEEDED(IMFMediaSink_QueryInterface(media_sink->sink, &IID_IMFMediaSinkPreroll, (void **)&media_sink->preroll)))
1177 session->presentation.flags |= SESSION_FLAG_NEEDS_PREROLL;
1180 list_add_tail(&session->presentation.sinks, &media_sink->entry);
1182 return S_OK;
1185 static DWORD transform_node_get_stream_id(struct topo_node *node, BOOL output, unsigned int index)
1187 DWORD *map = output ? node->u.transform.output_map : node->u.transform.input_map;
1188 return map ? map[index] : index;
1191 static HRESULT session_set_transform_stream_info(struct topo_node *node)
1193 DWORD *input_map = NULL, *output_map = NULL;
1194 DWORD i, input_count, output_count;
1195 struct transform_stream *streams;
1196 unsigned int block_alignment;
1197 IMFMediaType *media_type;
1198 GUID major = { 0 };
1199 HRESULT hr;
1201 hr = IMFTransform_GetStreamCount(node->object.transform, &input_count, &output_count);
1202 if (SUCCEEDED(hr) && (input_count > 1 || output_count > 1))
1204 input_map = calloc(input_count, sizeof(*input_map));
1205 output_map = calloc(output_count, sizeof(*output_map));
1206 if (FAILED(IMFTransform_GetStreamIDs(node->object.transform, input_count, input_map,
1207 output_count, output_map)))
1209 /* Assume sequential identifiers. */
1210 free(input_map);
1211 free(output_map);
1212 input_map = output_map = NULL;
1216 if (SUCCEEDED(hr))
1218 node->u.transform.input_map = input_map;
1219 node->u.transform.output_map = output_map;
1221 streams = calloc(input_count, sizeof(*streams));
1222 for (i = 0; i < input_count; ++i)
1223 list_init(&streams[i].samples);
1224 node->u.transform.inputs = streams;
1225 node->u.transform.input_count = input_count;
1227 streams = calloc(output_count, sizeof(*streams));
1228 for (i = 0; i < output_count; ++i)
1230 list_init(&streams[i].samples);
1232 if (SUCCEEDED(IMFTransform_GetOutputCurrentType(node->object.transform,
1233 transform_node_get_stream_id(node, TRUE, i), &media_type)))
1235 if (SUCCEEDED(IMFMediaType_GetMajorType(media_type, &major)) && IsEqualGUID(&major, &MFMediaType_Audio)
1236 && SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment)))
1238 streams[i].min_buffer_size = block_alignment;
1240 IMFMediaType_Release(media_type);
1243 node->u.transform.outputs = streams;
1244 node->u.transform.output_count = output_count;
1247 return hr;
1250 static HRESULT session_get_stream_sink_type(IMFStreamSink *sink, IMFMediaType **media_type)
1252 IMFMediaTypeHandler *handler;
1253 HRESULT hr;
1255 if (SUCCEEDED(hr = IMFStreamSink_GetMediaTypeHandler(sink, &handler)))
1257 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, media_type);
1258 IMFMediaTypeHandler_Release(handler);
1261 return hr;
1264 static HRESULT WINAPI node_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify *iface,
1265 REFIID riid, void **obj)
1267 if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorNotify) ||
1268 IsEqualIID(riid, &IID_IUnknown))
1270 *obj = iface;
1271 IMFVideoSampleAllocatorNotify_AddRef(iface);
1272 return S_OK;
1275 *obj = NULL;
1276 return E_NOINTERFACE;
1279 static ULONG WINAPI node_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify *iface)
1281 return 2;
1284 static ULONG WINAPI node_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify *iface)
1286 return 1;
1289 static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output);
1291 static HRESULT WINAPI node_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify *iface)
1293 struct topo_node *topo_node = impl_node_from_IMFVideoSampleAllocatorNotify(iface);
1294 struct session_op *op;
1296 if (SUCCEEDED(create_session_op(SESSION_CMD_SA_READY, &op)))
1298 op->u.sa_ready.node_id = topo_node->node_id;
1299 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &topo_node->session->commands_callback, &op->IUnknown_iface);
1300 IUnknown_Release(&op->IUnknown_iface);
1303 return S_OK;
1306 static const IMFVideoSampleAllocatorNotifyVtbl node_sample_allocator_cb_vtbl =
1308 node_sample_allocator_cb_QueryInterface,
1309 node_sample_allocator_cb_AddRef,
1310 node_sample_allocator_cb_Release,
1311 node_sample_allocator_cb_NotifyRelease,
1314 static HRESULT session_append_node(struct media_session *session, IMFTopologyNode *node)
1316 struct topo_node *topo_node;
1317 IMFMediaSink *media_sink;
1318 IMFMediaType *media_type;
1319 IMFStreamDescriptor *sd;
1320 HRESULT hr = S_OK;
1322 if (!(topo_node = calloc(1, sizeof(*topo_node))))
1323 return E_OUTOFMEMORY;
1325 IMFTopologyNode_GetNodeType(node, &topo_node->type);
1326 IMFTopologyNode_GetTopoNodeID(node, &topo_node->node_id);
1327 topo_node->node = node;
1328 IMFTopologyNode_AddRef(topo_node->node);
1329 topo_node->session = session;
1331 switch (topo_node->type)
1333 case MF_TOPOLOGY_OUTPUT_NODE:
1334 topo_node->u.sink.notify_cb.lpVtbl = &node_sample_allocator_cb_vtbl;
1336 if (FAILED(hr = topology_node_get_object(node, &IID_IMFStreamSink, (void **)&topo_node->object.object)))
1338 WARN("Failed to get stream sink interface, hr %#x.\n", hr);
1339 break;
1342 if (FAILED(hr = IMFStreamSink_GetMediaSink(topo_node->object.sink_stream, &media_sink)))
1343 break;
1345 if (SUCCEEDED(hr = session_add_media_sink(session, node, media_sink)))
1347 if (SUCCEEDED(session_get_stream_sink_type(topo_node->object.sink_stream, &media_type)))
1349 if (SUCCEEDED(MFGetService(topo_node->object.object, &MR_VIDEO_ACCELERATION_SERVICE,
1350 &IID_IMFVideoSampleAllocator, (void **)&topo_node->u.sink.allocator)))
1352 if (FAILED(hr = IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node->u.sink.allocator,
1353 2, media_type)))
1355 WARN("Failed to initialize sample allocator for the stream, hr %#x.\n", hr);
1357 IMFVideoSampleAllocator_QueryInterface(topo_node->u.sink.allocator,
1358 &IID_IMFVideoSampleAllocatorCallback, (void **)&topo_node->u.sink.allocator_cb);
1359 IMFVideoSampleAllocatorCallback_SetCallback(topo_node->u.sink.allocator_cb,
1360 &topo_node->u.sink.notify_cb);
1362 IMFMediaType_Release(media_type);
1365 IMFMediaSink_Release(media_sink);
1367 break;
1368 case MF_TOPOLOGY_SOURCESTREAM_NODE:
1369 if (FAILED(IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_SOURCE, &IID_IMFMediaSource,
1370 (void **)&topo_node->u.source.source)))
1372 WARN("Missing MF_TOPONODE_SOURCE, hr %#x.\n", hr);
1373 break;
1376 if (FAILED(hr = session_add_media_source(session, node, topo_node->u.source.source)))
1377 break;
1379 if (FAILED(hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR,
1380 &IID_IMFStreamDescriptor, (void **)&sd)))
1382 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#x.\n", hr);
1383 break;
1386 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &topo_node->u.source.stream_id);
1387 IMFStreamDescriptor_Release(sd);
1389 break;
1390 case MF_TOPOLOGY_TRANSFORM_NODE:
1392 if (SUCCEEDED(hr = topology_node_get_object(node, &IID_IMFTransform, (void **)&topo_node->object.transform)))
1394 hr = session_set_transform_stream_info(topo_node);
1396 else
1397 WARN("Failed to get IMFTransform for MFT node, hr %#x.\n", hr);
1399 break;
1400 case MF_TOPOLOGY_TEE_NODE:
1401 FIXME("Unsupported node type %d.\n", topo_node->type);
1403 break;
1404 default:
1408 if (SUCCEEDED(hr))
1409 list_add_tail(&session->presentation.nodes, &topo_node->entry);
1410 else
1411 release_topo_node(topo_node);
1413 return hr;
1416 static HRESULT session_collect_nodes(struct media_session *session)
1418 IMFTopology *topology = session->presentation.current_topology;
1419 IMFTopologyNode *node;
1420 WORD i, count = 0;
1421 HRESULT hr;
1423 if (!list_empty(&session->presentation.nodes))
1424 return S_OK;
1426 if (FAILED(hr = IMFTopology_GetNodeCount(topology, &count)))
1427 return hr;
1429 for (i = 0; i < count; ++i)
1431 if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
1433 WARN("Failed to get node %u.\n", i);
1434 break;
1437 hr = session_append_node(session, node);
1438 IMFTopologyNode_Release(node);
1439 if (FAILED(hr))
1441 WARN("Failed to add node %u.\n", i);
1442 break;
1446 return hr;
1449 static HRESULT session_set_current_topology(struct media_session *session, IMFTopology *topology)
1451 struct media_source *source;
1452 DWORD caps, object_flags;
1453 struct media_sink *sink;
1454 struct topo_node *node;
1455 struct session_op *op;
1456 IMFMediaEvent *event;
1457 HRESULT hr;
1459 if (session->quality_manager)
1461 if (SUCCEEDED(create_session_op(SESSION_CMD_QM_NOTIFY_TOPOLOGY, &op)))
1463 op->u.notify_topology.topology = topology;
1464 IMFTopology_AddRef(op->u.notify_topology.topology);
1465 session_submit_command(session, op);
1466 IUnknown_Release(&op->IUnknown_iface);
1470 if (FAILED(hr = IMFTopology_CloneFrom(session->presentation.current_topology, topology)))
1472 WARN("Failed to clone topology, hr %#x.\n", hr);
1473 return hr;
1476 session_collect_nodes(session);
1478 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
1480 if (node->type == MF_TOPOLOGY_TRANSFORM_NODE)
1482 if (FAILED(hr = IMFTransform_ProcessMessage(node->object.transform,
1483 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0)))
1484 return hr;
1488 /* FIXME: attributes are all zero for now */
1489 if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime, &GUID_NULL, S_OK, NULL, &event)))
1491 IMFMediaEvent_SetUINT64(event, &MF_EVENT_START_PRESENTATION_TIME, 0);
1492 IMFMediaEvent_SetUINT64(event, &MF_EVENT_PRESENTATION_TIME_OFFSET, 0);
1493 IMFMediaEvent_SetUINT64(event, &MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT, 0);
1495 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
1496 IMFMediaEvent_Release(event);
1499 /* Update session caps. */
1500 caps = MFSESSIONCAP_START | MFSESSIONCAP_SEEK | MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE |
1501 MFSESSIONCAP_DOES_NOT_USE_NETWORK;
1503 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
1505 if (!caps)
1506 break;
1508 object_flags = 0;
1509 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source->source, &object_flags)))
1511 if (!(object_flags & MFMEDIASOURCE_DOES_NOT_USE_NETWORK))
1512 caps &= ~MFSESSIONCAP_DOES_NOT_USE_NETWORK;
1513 if (!(object_flags & MFMEDIASOURCE_CAN_SEEK))
1514 caps &= ~MFSESSIONCAP_SEEK;
1517 /* Mask unsupported rate caps. */
1519 caps &= session_get_object_rate_caps(source->object)
1520 | ~(MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE);
1523 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
1525 if (!caps)
1526 break;
1528 object_flags = 0;
1529 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink->sink, &object_flags)))
1531 if (!(object_flags & MEDIASINK_RATELESS))
1532 caps &= session_get_object_rate_caps(sink->object)
1533 | ~(MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE);
1537 session_set_caps(session, caps);
1539 return S_OK;
1542 static void session_set_topology(struct media_session *session, DWORD flags, IMFTopology *topology)
1544 IMFTopology *resolved_topology = NULL;
1545 HRESULT hr = S_OK;
1547 /* Resolve unless claimed to be full. */
1548 if (!(flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT) && topology)
1550 if (!(flags & MFSESSION_SETTOPOLOGY_NORESOLUTION))
1552 hr = session_bind_output_nodes(topology);
1554 if (SUCCEEDED(hr))
1555 hr = IMFTopoLoader_Load(session->topo_loader, topology, &resolved_topology, NULL /* FIXME? */);
1557 if (SUCCEEDED(hr))
1559 topology = resolved_topology;
1564 if (flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT)
1566 if ((topology && topology == session->presentation.current_topology) || !topology)
1568 /* FIXME: stop current topology, queue next one. */
1569 session_clear_presentation(session);
1571 else
1572 hr = S_FALSE;
1574 topology = NULL;
1576 else if (topology && flags & MFSESSION_SETTOPOLOGY_IMMEDIATE)
1578 session_clear_queued_topologies(session);
1579 session_clear_presentation(session);
1582 session_raise_topology_set(session, topology, hr);
1584 /* With no current topology set it right away, otherwise queue. */
1585 if (topology)
1587 struct queued_topology *queued_topology;
1589 if ((queued_topology = calloc(1, sizeof(*queued_topology))))
1591 queued_topology->topology = topology;
1592 IMFTopology_AddRef(queued_topology->topology);
1594 list_add_tail(&session->topologies, &queued_topology->entry);
1597 if (session->presentation.topo_status == MF_TOPOSTATUS_INVALID)
1599 hr = session_set_current_topology(session, topology);
1600 session_set_topo_status(session, hr, MF_TOPOSTATUS_READY);
1604 if (resolved_topology)
1605 IMFTopology_Release(resolved_topology);
1608 static HRESULT WINAPI mfsession_QueryInterface(IMFMediaSession *iface, REFIID riid, void **out)
1610 struct media_session *session = impl_from_IMFMediaSession(iface);
1612 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1614 *out = NULL;
1616 if (IsEqualIID(riid, &IID_IMFMediaSession) ||
1617 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
1618 IsEqualIID(riid, &IID_IUnknown))
1620 *out = &session->IMFMediaSession_iface;
1622 else if (IsEqualIID(riid, &IID_IMFGetService))
1624 *out = &session->IMFGetService_iface;
1626 else if (IsEqualIID(riid, &IID_IMFRateSupport))
1628 *out = &session->IMFRateSupport_iface;
1630 else if (IsEqualIID(riid, &IID_IMFRateControl))
1632 *out = &session->IMFRateControl_iface;
1635 if (*out)
1637 IMFMediaSession_AddRef(iface);
1638 return S_OK;
1641 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1642 return E_NOINTERFACE;
1645 static ULONG WINAPI mfsession_AddRef(IMFMediaSession *iface)
1647 struct media_session *session = impl_from_IMFMediaSession(iface);
1648 ULONG refcount = InterlockedIncrement(&session->refcount);
1650 TRACE("%p, refcount %u.\n", iface, refcount);
1652 return refcount;
1655 static ULONG WINAPI mfsession_Release(IMFMediaSession *iface)
1657 struct media_session *session = impl_from_IMFMediaSession(iface);
1658 ULONG refcount = InterlockedDecrement(&session->refcount);
1660 TRACE("%p, refcount %u.\n", iface, refcount);
1662 if (!refcount)
1664 session_clear_queued_topologies(session);
1665 session_clear_presentation(session);
1666 session_clear_command_list(session);
1667 if (session->presentation.current_topology)
1668 IMFTopology_Release(session->presentation.current_topology);
1669 if (session->event_queue)
1670 IMFMediaEventQueue_Release(session->event_queue);
1671 if (session->clock)
1672 IMFPresentationClock_Release(session->clock);
1673 if (session->system_time_source)
1674 IMFPresentationTimeSource_Release(session->system_time_source);
1675 if (session->clock_rate_control)
1676 IMFRateControl_Release(session->clock_rate_control);
1677 if (session->topo_loader)
1678 IMFTopoLoader_Release(session->topo_loader);
1679 if (session->quality_manager)
1680 IMFQualityManager_Release(session->quality_manager);
1681 DeleteCriticalSection(&session->cs);
1682 free(session);
1685 return refcount;
1688 static HRESULT WINAPI mfsession_GetEvent(IMFMediaSession *iface, DWORD flags, IMFMediaEvent **event)
1690 struct media_session *session = impl_from_IMFMediaSession(iface);
1692 TRACE("%p, %#x, %p.\n", iface, flags, event);
1694 return IMFMediaEventQueue_GetEvent(session->event_queue, flags, event);
1697 static HRESULT WINAPI mfsession_BeginGetEvent(IMFMediaSession *iface, IMFAsyncCallback *callback, IUnknown *state)
1699 struct media_session *session = impl_from_IMFMediaSession(iface);
1701 TRACE("%p, %p, %p.\n", iface, callback, state);
1703 return IMFMediaEventQueue_BeginGetEvent(session->event_queue, callback, state);
1706 static HRESULT WINAPI mfsession_EndGetEvent(IMFMediaSession *iface, IMFAsyncResult *result, IMFMediaEvent **event)
1708 struct media_session *session = impl_from_IMFMediaSession(iface);
1710 TRACE("%p, %p, %p.\n", iface, result, event);
1712 return IMFMediaEventQueue_EndGetEvent(session->event_queue, result, event);
1715 static HRESULT WINAPI mfsession_QueueEvent(IMFMediaSession *iface, MediaEventType event_type, REFGUID ext_type,
1716 HRESULT hr, const PROPVARIANT *value)
1718 struct media_session *session = impl_from_IMFMediaSession(iface);
1720 TRACE("%p, %d, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
1722 return IMFMediaEventQueue_QueueEventParamVar(session->event_queue, event_type, ext_type, hr, value);
1725 static HRESULT WINAPI mfsession_SetTopology(IMFMediaSession *iface, DWORD flags, IMFTopology *topology)
1727 struct media_session *session = impl_from_IMFMediaSession(iface);
1728 struct session_op *op;
1729 WORD node_count = 0;
1730 HRESULT hr;
1732 TRACE("%p, %#x, %p.\n", iface, flags, topology);
1734 if (topology)
1736 if (FAILED(IMFTopology_GetNodeCount(topology, &node_count)) || node_count == 0)
1737 return E_INVALIDARG;
1740 if (FAILED(hr = create_session_op(SESSION_CMD_SET_TOPOLOGY, &op)))
1741 return hr;
1743 op->u.set_topology.flags = flags;
1744 op->u.set_topology.topology = topology;
1745 if (op->u.set_topology.topology)
1746 IMFTopology_AddRef(op->u.set_topology.topology);
1748 hr = session_submit_command(session, op);
1749 IUnknown_Release(&op->IUnknown_iface);
1751 return hr;
1754 static HRESULT WINAPI mfsession_ClearTopologies(IMFMediaSession *iface)
1756 struct media_session *session = impl_from_IMFMediaSession(iface);
1758 TRACE("%p.\n", iface);
1760 return session_submit_simple_command(session, SESSION_CMD_CLEAR_TOPOLOGIES);
1763 static HRESULT WINAPI mfsession_Start(IMFMediaSession *iface, const GUID *format, const PROPVARIANT *start_position)
1765 struct media_session *session = impl_from_IMFMediaSession(iface);
1766 struct session_op *op;
1767 HRESULT hr;
1769 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), start_position);
1771 if (!start_position)
1772 return E_POINTER;
1774 if (FAILED(hr = create_session_op(SESSION_CMD_START, &op)))
1775 return hr;
1777 op->u.start.time_format = format ? *format : GUID_NULL;
1778 hr = PropVariantCopy(&op->u.start.start_position, start_position);
1780 if (SUCCEEDED(hr))
1781 hr = session_submit_command(session, op);
1783 IUnknown_Release(&op->IUnknown_iface);
1784 return hr;
1787 static HRESULT WINAPI mfsession_Pause(IMFMediaSession *iface)
1789 struct media_session *session = impl_from_IMFMediaSession(iface);
1791 TRACE("%p.\n", iface);
1793 return session_submit_simple_command(session, SESSION_CMD_PAUSE);
1796 static HRESULT WINAPI mfsession_Stop(IMFMediaSession *iface)
1798 struct media_session *session = impl_from_IMFMediaSession(iface);
1800 TRACE("%p.\n", iface);
1802 return session_submit_simple_command(session, SESSION_CMD_STOP);
1805 static HRESULT WINAPI mfsession_Close(IMFMediaSession *iface)
1807 struct media_session *session = impl_from_IMFMediaSession(iface);
1809 TRACE("%p.\n", iface);
1811 return session_submit_simple_command(session, SESSION_CMD_CLOSE);
1814 static HRESULT WINAPI mfsession_Shutdown(IMFMediaSession *iface)
1816 struct media_session *session = impl_from_IMFMediaSession(iface);
1817 HRESULT hr = S_OK;
1819 TRACE("%p.\n", iface);
1821 EnterCriticalSection(&session->cs);
1822 if (SUCCEEDED(hr = session_is_shut_down(session)))
1824 session->state = SESSION_STATE_SHUT_DOWN;
1825 IMFMediaEventQueue_Shutdown(session->event_queue);
1826 if (session->quality_manager)
1827 IMFQualityManager_Shutdown(session->quality_manager);
1828 MFShutdownObject((IUnknown *)session->clock);
1829 IMFPresentationClock_Release(session->clock);
1830 session->clock = NULL;
1831 session_clear_presentation(session);
1832 session_clear_command_list(session);
1834 LeaveCriticalSection(&session->cs);
1836 return hr;
1839 static HRESULT WINAPI mfsession_GetClock(IMFMediaSession *iface, IMFClock **clock)
1841 struct media_session *session = impl_from_IMFMediaSession(iface);
1842 HRESULT hr;
1844 TRACE("%p, %p.\n", iface, clock);
1846 EnterCriticalSection(&session->cs);
1847 if (SUCCEEDED(hr = session_is_shut_down(session)))
1849 *clock = (IMFClock *)session->clock;
1850 IMFClock_AddRef(*clock);
1852 LeaveCriticalSection(&session->cs);
1854 return hr;
1857 static HRESULT WINAPI mfsession_GetSessionCapabilities(IMFMediaSession *iface, DWORD *caps)
1859 struct media_session *session = impl_from_IMFMediaSession(iface);
1860 HRESULT hr = S_OK;
1862 TRACE("%p, %p.\n", iface, caps);
1864 if (!caps)
1865 return E_POINTER;
1867 EnterCriticalSection(&session->cs);
1868 if (SUCCEEDED(hr = session_is_shut_down(session)))
1869 *caps = session->caps;
1870 LeaveCriticalSection(&session->cs);
1872 return hr;
1875 static HRESULT WINAPI mfsession_GetFullTopology(IMFMediaSession *iface, DWORD flags, TOPOID id, IMFTopology **topology)
1877 struct media_session *session = impl_from_IMFMediaSession(iface);
1878 struct queued_topology *queued;
1879 TOPOID topo_id;
1880 HRESULT hr;
1882 TRACE("%p, %#x, %s, %p.\n", iface, flags, wine_dbgstr_longlong(id), topology);
1884 *topology = NULL;
1886 EnterCriticalSection(&session->cs);
1888 if (SUCCEEDED(hr = session_is_shut_down(session)))
1890 if (flags & MFSESSION_GETFULLTOPOLOGY_CURRENT)
1892 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
1893 *topology = session->presentation.current_topology;
1894 else
1895 hr = MF_E_INVALIDREQUEST;
1897 else
1899 LIST_FOR_EACH_ENTRY(queued, &session->topologies, struct queued_topology, entry)
1901 if (SUCCEEDED(IMFTopology_GetTopologyID(queued->topology, &topo_id)) && topo_id == id)
1903 *topology = queued->topology;
1904 break;
1909 if (*topology)
1910 IMFTopology_AddRef(*topology);
1913 LeaveCriticalSection(&session->cs);
1915 return hr;
1918 static const IMFMediaSessionVtbl mfmediasessionvtbl =
1920 mfsession_QueryInterface,
1921 mfsession_AddRef,
1922 mfsession_Release,
1923 mfsession_GetEvent,
1924 mfsession_BeginGetEvent,
1925 mfsession_EndGetEvent,
1926 mfsession_QueueEvent,
1927 mfsession_SetTopology,
1928 mfsession_ClearTopologies,
1929 mfsession_Start,
1930 mfsession_Pause,
1931 mfsession_Stop,
1932 mfsession_Close,
1933 mfsession_Shutdown,
1934 mfsession_GetClock,
1935 mfsession_GetSessionCapabilities,
1936 mfsession_GetFullTopology,
1939 static HRESULT WINAPI session_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1941 struct media_session *session = impl_from_IMFGetService(iface);
1942 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
1945 static ULONG WINAPI session_get_service_AddRef(IMFGetService *iface)
1947 struct media_session *session = impl_from_IMFGetService(iface);
1948 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
1951 static ULONG WINAPI session_get_service_Release(IMFGetService *iface)
1953 struct media_session *session = impl_from_IMFGetService(iface);
1954 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
1957 typedef BOOL (*p_renderer_node_test_func)(IMFMediaSink *sink);
1959 static BOOL session_video_renderer_test_func(IMFMediaSink *sink)
1961 IUnknown *obj;
1962 HRESULT hr;
1964 /* Use first sink to support IMFVideoRenderer. */
1965 hr = IMFMediaSink_QueryInterface(sink, &IID_IMFVideoRenderer, (void **)&obj);
1966 if (obj)
1967 IUnknown_Release(obj);
1969 return hr == S_OK;
1972 static BOOL session_audio_renderer_test_func(IMFMediaSink *sink)
1974 return mf_is_sar_sink(sink);
1977 static HRESULT session_get_renderer_node_service(struct media_session *session,
1978 p_renderer_node_test_func node_test_func, REFGUID service, REFIID riid, void **obj)
1980 HRESULT hr = E_NOINTERFACE;
1981 IMFStreamSink *stream_sink;
1982 IMFTopologyNode *node;
1983 IMFCollection *nodes;
1984 IMFMediaSink *sink;
1985 unsigned int i = 0;
1987 if (session->presentation.current_topology)
1989 if (SUCCEEDED(IMFTopology_GetOutputNodeCollection(session->presentation.current_topology,
1990 &nodes)))
1992 while (IMFCollection_GetElement(nodes, i++, (IUnknown **)&node) == S_OK)
1994 if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink)))
1996 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink)))
1998 if (node_test_func(sink))
2000 if (FAILED(hr = MFGetService((IUnknown *)sink, service, riid, obj)))
2001 WARN("Failed to get service from renderer node, %#x.\n", hr);
2004 IMFStreamSink_Release(stream_sink);
2007 IMFTopologyNode_Release(node);
2009 if (*obj)
2010 break;
2013 IMFCollection_Release(nodes);
2017 return hr;
2020 static HRESULT session_get_audio_render_service(struct media_session *session, REFGUID service,
2021 REFIID riid, void **obj)
2023 return session_get_renderer_node_service(session, session_audio_renderer_test_func,
2024 service, riid, obj);
2027 static HRESULT session_get_video_render_service(struct media_session *session, REFGUID service,
2028 REFIID riid, void **obj)
2030 return session_get_renderer_node_service(session, session_video_renderer_test_func,
2031 service, riid, obj);
2034 static HRESULT WINAPI session_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
2036 struct media_session *session = impl_from_IMFGetService(iface);
2037 HRESULT hr = S_OK;
2039 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
2041 *obj = NULL;
2043 EnterCriticalSection(&session->cs);
2044 if (FAILED(hr = session_is_shut_down(session)))
2047 else if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE))
2049 if (IsEqualIID(riid, &IID_IMFRateSupport))
2051 *obj = &session->IMFRateSupport_iface;
2053 else if (IsEqualIID(riid, &IID_IMFRateControl))
2055 *obj = &session->IMFRateControl_iface;
2057 else
2058 hr = E_NOINTERFACE;
2060 if (*obj)
2061 IUnknown_AddRef((IUnknown *)*obj);
2063 else if (IsEqualGUID(service, &MF_LOCAL_MFT_REGISTRATION_SERVICE))
2065 hr = IMFLocalMFTRegistration_QueryInterface(&local_mft_registration, riid, obj);
2067 else if (IsEqualGUID(service, &MF_TOPONODE_ATTRIBUTE_EDITOR_SERVICE))
2069 *obj = &session->IMFTopologyNodeAttributeEditor_iface;
2070 IUnknown_AddRef((IUnknown *)*obj);
2072 else if (IsEqualGUID(service, &MR_VIDEO_RENDER_SERVICE))
2074 hr = session_get_video_render_service(session, service, riid, obj);
2076 else if (IsEqualGUID(service, &MR_POLICY_VOLUME_SERVICE) ||
2077 IsEqualGUID(service, &MR_STREAM_VOLUME_SERVICE))
2079 hr = session_get_audio_render_service(session, service, riid, obj);
2081 else
2082 FIXME("Unsupported service %s.\n", debugstr_guid(service));
2084 LeaveCriticalSection(&session->cs);
2086 return hr;
2089 static const IMFGetServiceVtbl session_get_service_vtbl =
2091 session_get_service_QueryInterface,
2092 session_get_service_AddRef,
2093 session_get_service_Release,
2094 session_get_service_GetService,
2097 static HRESULT WINAPI session_commands_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
2099 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
2100 IsEqualIID(riid, &IID_IUnknown))
2102 *obj = iface;
2103 IMFAsyncCallback_AddRef(iface);
2104 return S_OK;
2107 WARN("Unsupported %s.\n", debugstr_guid(riid));
2108 *obj = NULL;
2109 return E_NOINTERFACE;
2112 static ULONG WINAPI session_commands_callback_AddRef(IMFAsyncCallback *iface)
2114 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2115 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2118 static ULONG WINAPI session_commands_callback_Release(IMFAsyncCallback *iface)
2120 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2121 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2124 static HRESULT WINAPI session_commands_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
2126 return E_NOTIMPL;
2129 static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
2131 struct session_op *op = impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result));
2132 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2133 struct topo_node *topo_node;
2134 IMFTopologyNode *upstream_node;
2135 DWORD upstream_output;
2137 EnterCriticalSection(&session->cs);
2139 switch (op->command)
2141 case SESSION_CMD_CLEAR_TOPOLOGIES:
2142 session_clear_topologies(session);
2143 break;
2144 case SESSION_CMD_SET_TOPOLOGY:
2145 session_set_topology(session, op->u.set_topology.flags, op->u.set_topology.topology);
2146 session_command_complete(session);
2147 break;
2148 case SESSION_CMD_START:
2149 session_start(session, &op->u.start.time_format, &op->u.start.start_position);
2150 break;
2151 case SESSION_CMD_PAUSE:
2152 session_pause(session);
2153 break;
2154 case SESSION_CMD_STOP:
2155 session_stop(session);
2156 break;
2157 case SESSION_CMD_CLOSE:
2158 session_close(session);
2159 break;
2160 case SESSION_CMD_QM_NOTIFY_TOPOLOGY:
2161 IMFQualityManager_NotifyTopology(session->quality_manager, op->u.notify_topology.topology);
2162 session_command_complete(session);
2163 break;
2164 case SESSION_CMD_SA_READY:
2165 topo_node = session_get_node_by_id(session, op->u.sa_ready.node_id);
2167 if (topo_node->u.sink.requests)
2169 if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node->node, 0, &upstream_node, &upstream_output)))
2171 session_request_sample_from_node(session, upstream_node, upstream_output);
2172 IMFTopologyNode_Release(upstream_node);
2175 break;
2176 default:
2180 LeaveCriticalSection(&session->cs);
2182 return S_OK;
2185 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl =
2187 session_commands_callback_QueryInterface,
2188 session_commands_callback_AddRef,
2189 session_commands_callback_Release,
2190 session_commands_callback_GetParameters,
2191 session_commands_callback_Invoke,
2194 static HRESULT WINAPI session_events_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
2196 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
2197 IsEqualIID(riid, &IID_IUnknown))
2199 *obj = iface;
2200 IMFAsyncCallback_AddRef(iface);
2201 return S_OK;
2204 WARN("Unsupported %s.\n", debugstr_guid(riid));
2205 *obj = NULL;
2206 return E_NOINTERFACE;
2209 static ULONG WINAPI session_events_callback_AddRef(IMFAsyncCallback *iface)
2211 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
2212 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2215 static ULONG WINAPI session_events_callback_Release(IMFAsyncCallback *iface)
2217 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
2218 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2221 static HRESULT WINAPI session_events_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
2223 return E_NOTIMPL;
2226 static HRESULT session_add_media_stream(struct media_session *session, IMFMediaSource *source, IMFMediaStream *stream)
2228 struct topo_node *node;
2229 IMFStreamDescriptor *sd;
2230 DWORD stream_id = 0;
2231 HRESULT hr;
2233 if (FAILED(hr = IMFMediaStream_GetStreamDescriptor(stream, &sd)))
2234 return hr;
2236 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &stream_id);
2237 IMFStreamDescriptor_Release(sd);
2238 if (FAILED(hr))
2239 return hr;
2241 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2243 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->u.source.source == source
2244 && node->u.source.stream_id == stream_id)
2246 if (node->object.source_stream)
2248 WARN("Node already has stream set.\n");
2249 return S_FALSE;
2252 node->object.source_stream = stream;
2253 IMFMediaStream_AddRef(node->object.source_stream);
2254 break;
2258 return S_OK;
2261 static BOOL session_is_source_nodes_state(struct media_session *session, enum object_state state)
2263 struct media_source *source;
2264 struct topo_node *node;
2266 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2268 if (source->state != state)
2269 return FALSE;
2272 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2274 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->state != state)
2275 return FALSE;
2278 return TRUE;
2281 static BOOL session_is_output_nodes_state(struct media_session *session, enum object_state state)
2283 struct topo_node *node;
2285 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2287 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->state != state)
2288 return FALSE;
2291 return TRUE;
2294 static enum object_state session_get_object_state_for_event(MediaEventType event)
2296 switch (event)
2298 case MESourceStarted:
2299 case MEStreamStarted:
2300 case MEStreamSinkStarted:
2301 return OBJ_STATE_STARTED;
2302 case MESourcePaused:
2303 case MEStreamPaused:
2304 case MEStreamSinkPaused:
2305 return OBJ_STATE_PAUSED;
2306 case MESourceStopped:
2307 case MEStreamStopped:
2308 case MEStreamSinkStopped:
2309 return OBJ_STATE_STOPPED;
2310 case MEStreamSinkPrerolled:
2311 return OBJ_STATE_PREROLLED;
2312 default:
2313 return OBJ_STATE_INVALID;
2317 static void session_set_consumed_clock(IUnknown *object, IMFPresentationClock *clock)
2319 IMFClockConsumer *consumer;
2321 if (SUCCEEDED(IUnknown_QueryInterface(object, &IID_IMFClockConsumer, (void **)&consumer)))
2323 IMFClockConsumer_SetPresentationClock(consumer, clock);
2324 IMFClockConsumer_Release(consumer);
2328 static void session_set_presentation_clock(struct media_session *session)
2330 IMFPresentationTimeSource *time_source = NULL;
2331 struct media_source *source;
2332 struct media_sink *sink;
2333 struct topo_node *node;
2334 HRESULT hr;
2336 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2338 if (node->type == MF_TOPOLOGY_TRANSFORM_NODE)
2339 IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
2342 if (!(session->presentation.flags & SESSION_FLAG_PRESENTATION_CLOCK_SET))
2344 /* Attempt to get time source from the sinks. */
2345 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2347 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink->sink, &IID_IMFPresentationTimeSource,
2348 (void **)&time_source)))
2349 break;
2352 if (time_source)
2354 hr = IMFPresentationClock_SetTimeSource(session->clock, time_source);
2355 IMFPresentationTimeSource_Release(time_source);
2357 else
2358 hr = IMFPresentationClock_SetTimeSource(session->clock, session->system_time_source);
2360 if (FAILED(hr))
2361 WARN("Failed to set time source, hr %#x.\n", hr);
2363 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2365 if (node->type != MF_TOPOLOGY_OUTPUT_NODE)
2366 continue;
2368 if (FAILED(hr = IMFStreamSink_BeginGetEvent(node->object.sink_stream, &session->events_callback,
2369 node->object.object)))
2371 WARN("Failed to subscribe to stream sink events, hr %#x.\n", hr);
2375 /* Set clock for all topology nodes. */
2376 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2378 session_set_consumed_clock(source->object, session->clock);
2381 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2383 if (sink->event_generator && FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(sink->event_generator,
2384 &session->events_callback, (IUnknown *)sink->event_generator)))
2386 WARN("Failed to subscribe to sink events, hr %#x.\n", hr);
2389 if (FAILED(hr = IMFMediaSink_SetPresentationClock(sink->sink, session->clock)))
2390 WARN("Failed to set presentation clock for the sink, hr %#x.\n", hr);
2393 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2395 if (node->type != MF_TOPOLOGY_TRANSFORM_NODE)
2396 continue;
2398 session_set_consumed_clock(node->object.object, session->clock);
2401 session->presentation.flags |= SESSION_FLAG_PRESENTATION_CLOCK_SET;
2405 static HRESULT session_start_clock(struct media_session *session)
2407 LONGLONG start_offset = 0;
2408 HRESULT hr;
2410 if (IsEqualGUID(&session->presentation.time_format, &GUID_NULL))
2412 if (session->presentation.start_position.vt == VT_EMPTY)
2413 start_offset = PRESENTATION_CURRENT_POSITION;
2414 else if (session->presentation.start_position.vt == VT_I8)
2415 start_offset = session->presentation.start_position.hVal.QuadPart;
2416 else
2417 FIXME("Unhandled position type %d.\n", session->presentation.start_position.vt);
2419 else
2420 FIXME("Unhandled time format %s.\n", debugstr_guid(&session->presentation.time_format));
2422 if (FAILED(hr = IMFPresentationClock_Start(session->clock, start_offset)))
2423 WARN("Failed to start session clock, hr %#x.\n", hr);
2425 return hr;
2428 static struct topo_node *session_get_node_object(struct media_session *session, IUnknown *object,
2429 MF_TOPOLOGY_TYPE node_type)
2431 struct topo_node *node = NULL;
2433 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2435 if (node->type == node_type && object == node->object.object)
2436 break;
2439 return node;
2442 static BOOL session_set_node_object_state(struct media_session *session, IUnknown *object,
2443 MF_TOPOLOGY_TYPE node_type, enum object_state state)
2445 struct topo_node *node;
2446 BOOL changed = FALSE;
2448 if ((node = session_get_node_object(session, object, node_type)))
2450 changed = node->state != state;
2451 node->state = state;
2454 return changed;
2457 static void session_set_source_object_state(struct media_session *session, IUnknown *object,
2458 MediaEventType event_type)
2460 IMFStreamSink *stream_sink;
2461 struct media_source *src;
2462 struct media_sink *sink;
2463 enum object_state state;
2464 struct topo_node *node;
2465 BOOL changed = FALSE;
2466 DWORD i, count;
2467 HRESULT hr;
2469 if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
2470 return;
2472 switch (event_type)
2474 case MESourceStarted:
2475 case MESourcePaused:
2476 case MESourceStopped:
2478 LIST_FOR_EACH_ENTRY(src, &session->presentation.sources, struct media_source, entry)
2480 if (object == src->object)
2482 changed = src->state != state;
2483 src->state = state;
2484 break;
2487 break;
2488 case MEStreamStarted:
2489 case MEStreamPaused:
2490 case MEStreamStopped:
2492 changed = session_set_node_object_state(session, object, MF_TOPOLOGY_SOURCESTREAM_NODE, state);
2493 default:
2497 if (!changed)
2498 return;
2500 switch (session->state)
2502 case SESSION_STATE_STARTING_SOURCES:
2503 if (!session_is_source_nodes_state(session, OBJ_STATE_STARTED))
2504 break;
2506 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_STARTED_SOURCE);
2508 session_set_presentation_clock(session);
2510 if (session->presentation.flags & SESSION_FLAG_NEEDS_PREROLL)
2512 MFTIME preroll_time = 0;
2514 if (session->presentation.start_position.vt == VT_I8)
2515 preroll_time = session->presentation.start_position.hVal.QuadPart;
2517 /* Mark stream sinks without prerolling support as PREROLLED to keep state test logic generic. */
2518 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2520 if (sink->preroll)
2522 /* FIXME: abort and enter error state on failure. */
2523 if (FAILED(hr = IMFMediaSinkPreroll_NotifyPreroll(sink->preroll, preroll_time)))
2524 WARN("Preroll notification failed, hr %#x.\n", hr);
2526 else
2528 if (SUCCEEDED(IMFMediaSink_GetStreamSinkCount(sink->sink, &count)))
2530 for (i = 0; i < count; ++i)
2532 if (SUCCEEDED(IMFMediaSink_GetStreamSinkByIndex(sink->sink, i, &stream_sink)))
2534 session_set_node_object_state(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE,
2535 OBJ_STATE_PREROLLED);
2536 IMFStreamSink_Release(stream_sink);
2542 session->state = SESSION_STATE_PREROLLING_SINKS;
2544 else if (SUCCEEDED(session_start_clock(session)))
2545 session->state = SESSION_STATE_STARTING_SINKS;
2547 break;
2548 case SESSION_STATE_PAUSING_SOURCES:
2549 if (!session_is_source_nodes_state(session, OBJ_STATE_PAUSED))
2550 break;
2552 session_set_paused(session, SESSION_STATE_PAUSED, S_OK);
2553 break;
2554 case SESSION_STATE_STOPPING_SOURCES:
2555 if (!session_is_source_nodes_state(session, OBJ_STATE_STOPPED))
2556 break;
2558 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2560 switch (node->type)
2562 case MF_TOPOLOGY_OUTPUT_NODE:
2563 IMFStreamSink_Flush(node->object.sink_stream);
2564 break;
2565 case MF_TOPOLOGY_TRANSFORM_NODE:
2566 IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_COMMAND_FLUSH, 0);
2567 break;
2568 default:
2573 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
2575 if (session->presentation.flags & SESSION_FLAG_FINALIZE_SINKS)
2576 session_finalize_sinks(session);
2577 else
2578 session_set_stopped(session, S_OK);
2580 break;
2581 default:
2586 static void session_set_sink_stream_state(struct media_session *session, IMFStreamSink *stream,
2587 MediaEventType event_type)
2589 struct media_source *source;
2590 enum object_state state;
2591 HRESULT hr = S_OK;
2592 BOOL changed;
2594 if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
2595 return;
2597 if (!(changed = session_set_node_object_state(session, (IUnknown *)stream, MF_TOPOLOGY_OUTPUT_NODE, state)))
2598 return;
2600 switch (session->state)
2602 case SESSION_STATE_PREROLLING_SINKS:
2603 if (!session_is_output_nodes_state(session, OBJ_STATE_PREROLLED))
2604 break;
2606 if (SUCCEEDED(session_start_clock(session)))
2607 session->state = SESSION_STATE_STARTING_SINKS;
2608 break;
2609 case SESSION_STATE_STARTING_SINKS:
2610 if (!session_is_output_nodes_state(session, OBJ_STATE_STARTED))
2611 break;
2613 session_set_started(session);
2614 break;
2615 case SESSION_STATE_PAUSING_SINKS:
2616 if (!session_is_output_nodes_state(session, OBJ_STATE_PAUSED))
2617 break;
2619 session->state = SESSION_STATE_PAUSING_SOURCES;
2621 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2623 if (FAILED(hr = IMFMediaSource_Pause(source->source)))
2624 break;
2627 if (FAILED(hr))
2628 session_set_paused(session, SESSION_STATE_PAUSED, hr);
2630 break;
2631 case SESSION_STATE_STOPPING_SINKS:
2632 if (!session_is_output_nodes_state(session, OBJ_STATE_STOPPED))
2633 break;
2635 session->state = SESSION_STATE_STOPPING_SOURCES;
2637 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2639 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION)
2640 IMFMediaSource_Stop(source->source);
2641 else if (FAILED(hr = IMFMediaSource_Stop(source->source)))
2642 break;
2645 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION || FAILED(hr))
2646 session_set_stopped(session, hr);
2648 break;
2649 default:
2654 static struct sample *transform_create_sample(IMFSample *sample)
2656 struct sample *sample_entry = calloc(1, sizeof(*sample_entry));
2658 if (sample_entry)
2660 sample_entry->sample = sample;
2661 if (sample_entry->sample)
2662 IMFSample_AddRef(sample_entry->sample);
2665 return sample_entry;
2668 static HRESULT transform_get_external_output_sample(const struct media_session *session, struct topo_node *transform,
2669 unsigned int output_index, const MFT_OUTPUT_STREAM_INFO *stream_info, IMFSample **sample)
2671 IMFTopologyNode *downstream_node;
2672 IMFMediaBuffer *buffer = NULL;
2673 struct topo_node *topo_node;
2674 unsigned int buffer_size;
2675 DWORD downstream_input;
2676 TOPOID node_id;
2677 HRESULT hr;
2679 if (FAILED(IMFTopologyNode_GetOutput(transform->node, output_index, &downstream_node, &downstream_input)))
2681 WARN("Failed to get connected node for output %u.\n", output_index);
2682 return MF_E_UNEXPECTED;
2685 IMFTopologyNode_GetTopoNodeID(downstream_node, &node_id);
2686 IMFTopologyNode_Release(downstream_node);
2688 topo_node = session_get_node_by_id(session, node_id);
2690 if (topo_node->type == MF_TOPOLOGY_OUTPUT_NODE && topo_node->u.sink.allocator)
2692 hr = IMFVideoSampleAllocator_AllocateSample(topo_node->u.sink.allocator, sample);
2694 else
2696 buffer_size = max(stream_info->cbSize, transform->u.transform.outputs[output_index].min_buffer_size);
2698 hr = MFCreateAlignedMemoryBuffer(buffer_size, stream_info->cbAlignment, &buffer);
2699 if (SUCCEEDED(hr))
2700 hr = MFCreateSample(sample);
2702 if (SUCCEEDED(hr))
2703 hr = IMFSample_AddBuffer(*sample, buffer);
2705 if (buffer)
2706 IMFMediaBuffer_Release(buffer);
2709 return hr;
2712 static HRESULT transform_node_pull_samples(const struct media_session *session, struct topo_node *node)
2714 MFT_OUTPUT_STREAM_INFO stream_info;
2715 MFT_OUTPUT_DATA_BUFFER *buffers;
2716 struct sample *queued_sample;
2717 HRESULT hr = E_UNEXPECTED;
2718 DWORD status = 0;
2719 unsigned int i;
2721 if (!(buffers = calloc(node->u.transform.output_count, sizeof(*buffers))))
2722 return E_OUTOFMEMORY;
2724 for (i = 0; i < node->u.transform.output_count; ++i)
2726 buffers[i].dwStreamID = transform_node_get_stream_id(node, TRUE, i);
2727 buffers[i].pSample = NULL;
2728 buffers[i].dwStatus = 0;
2729 buffers[i].pEvents = NULL;
2731 memset(&stream_info, 0, sizeof(stream_info));
2732 if (FAILED(hr = IMFTransform_GetOutputStreamInfo(node->object.transform, buffers[i].dwStreamID, &stream_info)))
2733 break;
2735 if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)))
2737 if (FAILED(hr = transform_get_external_output_sample(session, node, i, &stream_info, &buffers[i].pSample)))
2738 break;
2742 if (SUCCEEDED(hr))
2743 hr = IMFTransform_ProcessOutput(node->object.transform, 0, node->u.transform.output_count, buffers, &status);
2745 /* Collect returned samples for all streams. */
2746 for (i = 0; i < node->u.transform.output_count; ++i)
2748 if (buffers[i].pEvents)
2749 IMFCollection_Release(buffers[i].pEvents);
2751 if (SUCCEEDED(hr) && !(buffers[i].dwStatus & MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE))
2753 if (session->quality_manager)
2754 IMFQualityManager_NotifyProcessOutput(session->quality_manager, node->node, i, buffers[i].pSample);
2756 queued_sample = transform_create_sample(buffers[i].pSample);
2757 list_add_tail(&node->u.transform.outputs[i].samples, &queued_sample->entry);
2760 if (buffers[i].pSample)
2761 IMFSample_Release(buffers[i].pSample);
2764 free(buffers);
2766 return hr;
2769 static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input,
2770 IMFSample *sample)
2772 struct sample *sample_entry, *sample_entry2;
2773 DWORD stream_id, downstream_input;
2774 IMFTopologyNode *downstream_node;
2775 struct topo_node *topo_node;
2776 MF_TOPOLOGY_TYPE node_type;
2777 BOOL drain = FALSE;
2778 TOPOID node_id;
2779 unsigned int i;
2780 HRESULT hr;
2782 if (session->quality_manager)
2783 IMFQualityManager_NotifyProcessInput(session->quality_manager, node, input, sample);
2785 IMFTopologyNode_GetNodeType(node, &node_type);
2786 IMFTopologyNode_GetTopoNodeID(node, &node_id);
2788 topo_node = session_get_node_by_id(session, node_id);
2790 switch (node_type)
2792 case MF_TOPOLOGY_OUTPUT_NODE:
2793 if (sample)
2795 if (topo_node->u.sink.requests)
2797 if (FAILED(hr = IMFStreamSink_ProcessSample(topo_node->object.sink_stream, sample)))
2798 WARN("Stream sink failed to process sample, hr %#x.\n", hr);
2799 topo_node->u.sink.requests--;
2802 else if (FAILED(hr = IMFStreamSink_PlaceMarker(topo_node->object.sink_stream, MFSTREAMSINK_MARKER_ENDOFSEGMENT,
2803 NULL, NULL)))
2805 WARN("Failed to place sink marker, hr %#x.\n", hr);
2807 break;
2808 case MF_TOPOLOGY_TRANSFORM_NODE:
2810 transform_node_pull_samples(session, topo_node);
2812 sample_entry = transform_create_sample(sample);
2813 list_add_tail(&topo_node->u.transform.inputs[input].samples, &sample_entry->entry);
2815 for (i = 0; i < topo_node->u.transform.input_count; ++i)
2817 stream_id = transform_node_get_stream_id(topo_node, FALSE, i);
2818 LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.inputs[i].samples,
2819 struct sample, entry)
2821 if (sample_entry->sample)
2823 if ((hr = IMFTransform_ProcessInput(topo_node->object.transform, stream_id,
2824 sample_entry->sample, 0)) == MF_E_NOTACCEPTING)
2825 break;
2826 if (FAILED(hr))
2827 WARN("Failed to process input for stream %u/%u, hr %#x.\n", i, stream_id, hr);
2828 transform_release_sample(sample_entry);
2830 else
2832 transform_stream_drop_samples(&topo_node->u.transform.inputs[i]);
2833 drain = TRUE;
2838 if (drain)
2840 if (FAILED(hr = IMFTransform_ProcessMessage(topo_node->object.transform, MFT_MESSAGE_COMMAND_DRAIN, 0)))
2841 WARN("Drain command failed for transform, hr %#x.\n", hr);
2844 transform_node_pull_samples(session, topo_node);
2846 /* Remaining unprocessed input has been discarded, now queue markers for every output. */
2847 if (drain)
2849 for (i = 0; i < topo_node->u.transform.output_count; ++i)
2851 if ((sample_entry = transform_create_sample(NULL)))
2852 list_add_tail(&topo_node->u.transform.outputs[i].samples, &sample_entry->entry);
2856 /* Push down all available output. */
2857 for (i = 0; i < topo_node->u.transform.output_count; ++i)
2859 if (FAILED(IMFTopologyNode_GetOutput(node, i, &downstream_node, &downstream_input)))
2861 WARN("Failed to get connected node for output %u.\n", i);
2862 continue;
2865 LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.outputs[i].samples,
2866 struct sample, entry)
2868 if (!topo_node->u.transform.outputs[i].requests)
2869 break;
2871 session_deliver_sample_to_node(session, downstream_node, downstream_input, sample_entry->sample);
2872 topo_node->u.transform.outputs[i].requests--;
2874 transform_release_sample(sample_entry);
2877 IMFTopologyNode_Release(downstream_node);
2880 break;
2881 case MF_TOPOLOGY_TEE_NODE:
2882 FIXME("Unhandled downstream node type %d.\n", node_type);
2883 break;
2884 default:
2889 static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output)
2891 IMFTopologyNode *downstream_node, *upstream_node;
2892 DWORD downstream_input, upstream_output;
2893 struct topo_node *topo_node;
2894 MF_TOPOLOGY_TYPE node_type;
2895 struct sample *sample;
2896 TOPOID node_id;
2897 HRESULT hr;
2899 IMFTopologyNode_GetNodeType(node, &node_type);
2900 IMFTopologyNode_GetTopoNodeID(node, &node_id);
2902 topo_node = session_get_node_by_id(session, node_id);
2904 switch (node_type)
2906 case MF_TOPOLOGY_SOURCESTREAM_NODE:
2907 if (FAILED(hr = IMFMediaStream_RequestSample(topo_node->object.source_stream, NULL)))
2908 WARN("Sample request failed, hr %#x.\n", hr);
2909 break;
2910 case MF_TOPOLOGY_TRANSFORM_NODE:
2912 if (list_empty(&topo_node->u.transform.outputs[output].samples))
2914 /* Forward request to upstream node. */
2915 if (SUCCEEDED(hr = IMFTopologyNode_GetInput(node, 0 /* FIXME */, &upstream_node, &upstream_output)))
2917 if (SUCCEEDED(hr = session_request_sample_from_node(session, upstream_node, upstream_output)))
2918 topo_node->u.transform.outputs[output].requests++;
2919 IMFTopologyNode_Release(upstream_node);
2922 else
2924 if (SUCCEEDED(hr = IMFTopologyNode_GetOutput(node, output, &downstream_node, &downstream_input)))
2926 sample = LIST_ENTRY(list_head(&topo_node->u.transform.outputs[output].samples), struct sample, entry);
2927 session_deliver_sample_to_node(session, downstream_node, downstream_input, sample->sample);
2928 transform_release_sample(sample);
2929 IMFTopologyNode_Release(downstream_node);
2933 break;
2934 case MF_TOPOLOGY_TEE_NODE:
2935 FIXME("Unhandled upstream node type %d.\n", node_type);
2936 default:
2937 hr = E_UNEXPECTED;
2940 return hr;
2943 static void session_request_sample(struct media_session *session, IMFStreamSink *sink_stream)
2945 struct topo_node *sink_node = NULL, *node;
2946 IMFTopologyNode *upstream_node;
2947 DWORD upstream_output;
2948 HRESULT hr;
2950 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2952 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink_stream)
2954 sink_node = node;
2955 break;
2959 if (!sink_node)
2960 return;
2962 if (FAILED(hr = IMFTopologyNode_GetInput(sink_node->node, 0, &upstream_node, &upstream_output)))
2964 WARN("Failed to get upstream node connection, hr %#x.\n", hr);
2965 return;
2968 if (SUCCEEDED(session_request_sample_from_node(session, upstream_node, upstream_output)))
2969 sink_node->u.sink.requests++;
2970 IMFTopologyNode_Release(upstream_node);
2973 static void session_deliver_sample(struct media_session *session, IMFMediaStream *stream, const PROPVARIANT *value)
2975 struct topo_node *source_node = NULL, *node;
2976 IMFTopologyNode *downstream_node;
2977 DWORD downstream_input;
2978 HRESULT hr;
2980 if (value && (value->vt != VT_UNKNOWN || !value->punkVal))
2982 WARN("Unexpected value type %d.\n", value->vt);
2983 return;
2986 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2988 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->object.source_stream == stream)
2990 source_node = node;
2991 break;
2995 if (!source_node)
2996 return;
2998 if (!value)
2999 source_node->flags |= TOPO_NODE_END_OF_STREAM;
3001 if (FAILED(hr = IMFTopologyNode_GetOutput(source_node->node, 0, &downstream_node, &downstream_input)))
3003 WARN("Failed to get downstream node connection, hr %#x.\n", hr);
3004 return;
3007 session_deliver_sample_to_node(session, downstream_node, downstream_input, value ? (IMFSample *)value->punkVal : NULL);
3008 IMFTopologyNode_Release(downstream_node);
3011 static void session_sink_invalidated(struct media_session *session, IMFMediaEvent *event, IMFStreamSink *sink)
3013 struct topo_node *node, *sink_node = NULL;
3014 HRESULT hr;
3016 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
3018 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink)
3020 sink_node = node;
3021 break;
3025 if (!sink_node)
3026 return;
3028 if (!event)
3030 if (FAILED(hr = MFCreateMediaEvent(MESinkInvalidated, &GUID_NULL, S_OK, NULL, &event)))
3031 WARN("Failed to create event, hr %#x.\n", hr);
3034 if (!event)
3035 return;
3037 IMFMediaEvent_SetUINT64(event, &MF_EVENT_OUTPUT_NODE, sink_node->node_id);
3038 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3040 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED);
3043 static BOOL session_nodes_is_mask_set(struct media_session *session, MF_TOPOLOGY_TYPE node_type, unsigned int flags)
3045 struct media_source *source;
3046 struct topo_node *node;
3048 if (node_type == MF_TOPOLOGY_MAX)
3050 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3052 if ((source->flags & flags) != flags)
3053 return FALSE;
3056 else
3058 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
3060 if (node->type == node_type && (node->flags & flags) != flags)
3061 return FALSE;
3065 return TRUE;
3068 static void session_raise_end_of_presentation(struct media_session *session)
3070 if (!(session_nodes_is_mask_set(session, MF_TOPOLOGY_SOURCESTREAM_NODE, TOPO_NODE_END_OF_STREAM)))
3071 return;
3073 if (!(session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION))
3075 if (session_nodes_is_mask_set(session, MF_TOPOLOGY_MAX, SOURCE_FLAG_END_OF_PRESENTATION))
3077 session->presentation.flags |= SESSION_FLAG_END_OF_PRESENTATION;
3078 session_push_back_command(session, SESSION_CMD_END);
3079 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, NULL);
3084 static void session_handle_end_of_stream(struct media_session *session, IMFMediaStream *stream)
3086 struct topo_node *node;
3088 if (!(node = session_get_node_object(session, (IUnknown *)stream, MF_TOPOLOGY_SOURCESTREAM_NODE))
3089 || node->flags & TOPO_NODE_END_OF_STREAM)
3091 return;
3094 session_deliver_sample(session, stream, NULL);
3096 session_raise_end_of_presentation(session);
3099 static void session_handle_end_of_presentation(struct media_session *session, IMFMediaSource *object)
3101 struct media_source *source;
3103 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3105 if (source->source == object)
3107 if (!(source->flags & SOURCE_FLAG_END_OF_PRESENTATION))
3109 source->flags |= SOURCE_FLAG_END_OF_PRESENTATION;
3110 session_raise_end_of_presentation(session);
3113 break;
3118 static void session_sink_stream_marker(struct media_session *session, IMFStreamSink *stream_sink)
3120 struct topo_node *node;
3122 if (!(node = session_get_node_object(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE))
3123 || node->flags & TOPO_NODE_END_OF_STREAM)
3125 return;
3128 node->flags |= TOPO_NODE_END_OF_STREAM;
3130 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION &&
3131 session_nodes_is_mask_set(session, MF_TOPOLOGY_OUTPUT_NODE, TOPO_NODE_END_OF_STREAM))
3133 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED);
3134 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
3135 session_stop(session);
3139 static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
3141 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
3142 IMFMediaEventGenerator *event_source;
3143 IMFMediaEvent *event = NULL;
3144 MediaEventType event_type;
3145 IUnknown *object = NULL;
3146 IMFMediaSource *source;
3147 IMFMediaStream *stream;
3148 PROPVARIANT value;
3149 HRESULT hr;
3151 if (FAILED(hr = IMFAsyncResult_GetState(result, (IUnknown **)&event_source)))
3152 return hr;
3154 if (FAILED(hr = IMFMediaEventGenerator_EndGetEvent(event_source, result, &event)))
3156 WARN("Failed to get event from %p, hr %#x.\n", event_source, hr);
3157 goto failed;
3160 if (FAILED(hr = IMFMediaEvent_GetType(event, &event_type)))
3162 WARN("Failed to get event type, hr %#x.\n", hr);
3163 goto failed;
3166 value.vt = VT_EMPTY;
3167 if (FAILED(hr = IMFMediaEvent_GetValue(event, &value)))
3169 WARN("Failed to get event value, hr %#x.\n", hr);
3170 goto failed;
3173 switch (event_type)
3175 case MESourceStarted:
3176 case MESourcePaused:
3177 case MESourceStopped:
3178 case MEStreamStarted:
3179 case MEStreamPaused:
3180 case MEStreamStopped:
3182 EnterCriticalSection(&session->cs);
3183 session_set_source_object_state(session, (IUnknown *)event_source, event_type);
3184 LeaveCriticalSection(&session->cs);
3186 break;
3188 case MEBufferingStarted:
3189 case MEBufferingStopped:
3191 EnterCriticalSection(&session->cs);
3192 if (session_get_media_source(session, (IMFMediaSource *)event_source))
3194 if (event_type == MEBufferingStarted)
3195 IMFPresentationClock_Pause(session->clock);
3196 else
3197 IMFPresentationClock_Start(session->clock, PRESENTATION_CURRENT_POSITION);
3199 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3201 LeaveCriticalSection(&session->cs);
3202 break;
3204 case MEReconnectStart:
3205 case MEReconnectEnd:
3207 EnterCriticalSection(&session->cs);
3208 if (session_get_media_source(session, (IMFMediaSource *)event_source))
3209 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3210 LeaveCriticalSection(&session->cs);
3211 break;
3213 case MEExtendedType:
3214 case MERendererEvent:
3215 case MEStreamSinkFormatChanged:
3217 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3218 break;
3220 case MENewStream:
3221 stream = (IMFMediaStream *)value.punkVal;
3223 if (value.vt != VT_UNKNOWN || !stream)
3225 WARN("Unexpected event value.\n");
3226 break;
3229 if (FAILED(hr = IMFMediaStream_GetMediaSource(stream, &source)))
3230 break;
3232 EnterCriticalSection(&session->cs);
3233 if (SUCCEEDED(hr = session_add_media_stream(session, source, stream)))
3234 hr = IMFMediaStream_BeginGetEvent(stream, &session->events_callback, (IUnknown *)stream);
3235 LeaveCriticalSection(&session->cs);
3237 IMFMediaSource_Release(source);
3239 break;
3240 case MEStreamSinkStarted:
3241 case MEStreamSinkPaused:
3242 case MEStreamSinkStopped:
3243 case MEStreamSinkPrerolled:
3245 EnterCriticalSection(&session->cs);
3246 session_set_sink_stream_state(session, (IMFStreamSink *)event_source, event_type);
3247 LeaveCriticalSection(&session->cs);
3249 break;
3250 case MEStreamSinkMarker:
3252 EnterCriticalSection(&session->cs);
3253 session_sink_stream_marker(session, (IMFStreamSink *)event_source);
3254 LeaveCriticalSection(&session->cs);
3256 break;
3257 case MEStreamSinkRequestSample:
3259 EnterCriticalSection(&session->cs);
3260 session_request_sample(session, (IMFStreamSink *)event_source);
3261 LeaveCriticalSection(&session->cs);
3263 break;
3264 case MEMediaSample:
3266 EnterCriticalSection(&session->cs);
3267 session_deliver_sample(session, (IMFMediaStream *)event_source, &value);
3268 LeaveCriticalSection(&session->cs);
3270 break;
3271 case MEEndOfStream:
3273 EnterCriticalSection(&session->cs);
3274 session_handle_end_of_stream(session, (IMFMediaStream *)event_source);
3275 LeaveCriticalSection(&session->cs);
3277 break;
3279 case MEEndOfPresentation:
3281 EnterCriticalSection(&session->cs);
3282 session_handle_end_of_presentation(session, (IMFMediaSource *)event_source);
3283 LeaveCriticalSection(&session->cs);
3285 break;
3286 case MEAudioSessionGroupingParamChanged:
3287 case MEAudioSessionIconChanged:
3288 case MEAudioSessionNameChanged:
3289 case MEAudioSessionVolumeChanged:
3291 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3293 break;
3294 case MEAudioSessionDeviceRemoved:
3295 case MEAudioSessionDisconnected:
3296 case MEAudioSessionExclusiveModeOverride:
3297 case MEAudioSessionFormatChanged:
3298 case MEAudioSessionServerShutdown:
3300 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3301 /* fallthrough */
3302 case MESinkInvalidated:
3304 EnterCriticalSection(&session->cs);
3305 session_sink_invalidated(session, event_type == MESinkInvalidated ? event : NULL,
3306 (IMFStreamSink *)event_source);
3307 LeaveCriticalSection(&session->cs);
3309 break;
3310 case MEQualityNotify:
3312 if (session->quality_manager)
3314 if (FAILED(IMFMediaEventGenerator_QueryInterface(event_source, &IID_IMFStreamSink, (void **)&object)))
3315 IMFMediaEventGenerator_QueryInterface(event_source, &IID_IMFTransform, (void **)&object);
3317 if (object)
3319 IMFQualityManager_NotifyQualityEvent(session->quality_manager, object, event);
3320 IUnknown_Release(object);
3324 break;
3325 default:
3329 PropVariantClear(&value);
3331 failed:
3332 if (event)
3333 IMFMediaEvent_Release(event);
3335 if (FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(event_source, iface, (IUnknown *)event_source)))
3336 WARN("Failed to re-subscribe, hr %#x.\n", hr);
3338 IMFMediaEventGenerator_Release(event_source);
3340 return hr;
3343 static const IMFAsyncCallbackVtbl session_events_callback_vtbl =
3345 session_events_callback_QueryInterface,
3346 session_events_callback_AddRef,
3347 session_events_callback_Release,
3348 session_events_callback_GetParameters,
3349 session_events_callback_Invoke,
3352 static HRESULT WINAPI session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
3354 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
3355 IsEqualIID(riid, &IID_IUnknown))
3357 *obj = iface;
3358 IMFAsyncCallback_AddRef(iface);
3359 return S_OK;
3362 WARN("Unsupported %s.\n", debugstr_guid(riid));
3363 *obj = NULL;
3364 return E_NOINTERFACE;
3367 static ULONG WINAPI session_sink_finalizer_callback_AddRef(IMFAsyncCallback *iface)
3369 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3370 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3373 static ULONG WINAPI session_sink_finalizer_callback_Release(IMFAsyncCallback *iface)
3375 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3376 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3379 static HRESULT WINAPI session_sink_finalizer_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
3381 return E_NOTIMPL;
3384 static HRESULT WINAPI session_sink_finalizer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
3386 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3387 IMFFinalizableMediaSink *fin_sink = NULL;
3388 BOOL sinks_finalized = TRUE;
3389 struct media_sink *sink;
3390 IUnknown *state;
3391 HRESULT hr;
3393 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
3394 return hr;
3396 EnterCriticalSection(&session->cs);
3398 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
3400 if (state == sink->object)
3402 if (FAILED(hr = IMFMediaSink_QueryInterface(sink->sink, &IID_IMFFinalizableMediaSink, (void **)&fin_sink)))
3403 WARN("Unexpected, missing IMFFinalizableMediaSink, hr %#x.\n", hr);
3405 else
3407 sinks_finalized &= sink->finalized;
3408 if (!sinks_finalized)
3409 break;
3413 IUnknown_Release(state);
3415 if (fin_sink)
3417 /* Complete session transition, or close prematurely on error. */
3418 if (SUCCEEDED(hr = IMFFinalizableMediaSink_EndFinalize(fin_sink, result)))
3420 sink->finalized = TRUE;
3421 if (sinks_finalized)
3422 session_set_closed(session, hr);
3424 IMFFinalizableMediaSink_Release(fin_sink);
3427 LeaveCriticalSection(&session->cs);
3429 return S_OK;
3432 static const IMFAsyncCallbackVtbl session_sink_finalizer_callback_vtbl =
3434 session_sink_finalizer_callback_QueryInterface,
3435 session_sink_finalizer_callback_AddRef,
3436 session_sink_finalizer_callback_Release,
3437 session_sink_finalizer_callback_GetParameters,
3438 session_sink_finalizer_callback_Invoke,
3441 static HRESULT WINAPI session_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
3443 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3444 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
3447 static ULONG WINAPI session_rate_support_AddRef(IMFRateSupport *iface)
3449 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3450 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3453 static ULONG WINAPI session_rate_support_Release(IMFRateSupport *iface)
3455 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3456 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3459 static HRESULT session_presentation_object_get_rate(IUnknown *object, MFRATE_DIRECTION direction,
3460 BOOL thin, BOOL fastest, float *result)
3462 IMFRateSupport *rate_support;
3463 float rate;
3464 HRESULT hr;
3466 /* For objects that don't support rate control, it's assumed that only forward direction is allowed, at 1.0f. */
3468 if (FAILED(hr = MFGetService(object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support)))
3470 if (direction == MFRATE_FORWARD)
3472 *result = 1.0f;
3473 return S_OK;
3475 else
3476 return MF_E_REVERSE_UNSUPPORTED;
3479 rate = 0.0f;
3480 if (fastest)
3482 if (SUCCEEDED(hr = IMFRateSupport_GetFastestRate(rate_support, direction, thin, &rate)))
3483 *result = min(fabsf(rate), *result);
3485 else
3487 if (SUCCEEDED(hr = IMFRateSupport_GetSlowestRate(rate_support, direction, thin, &rate)))
3488 *result = max(fabsf(rate), *result);
3491 IMFRateSupport_Release(rate_support);
3493 return hr;
3496 static HRESULT session_get_presentation_rate(struct media_session *session, MFRATE_DIRECTION direction,
3497 BOOL thin, BOOL fastest, float *result)
3499 struct media_source *source;
3500 struct media_sink *sink;
3501 HRESULT hr = E_POINTER;
3502 float rate;
3504 rate = fastest ? FLT_MAX : 0.0f;
3506 EnterCriticalSection(&session->cs);
3508 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
3510 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3512 if (FAILED(hr = session_presentation_object_get_rate(source->object, direction, thin, fastest, &rate)))
3513 break;
3516 if (SUCCEEDED(hr))
3518 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
3520 if (FAILED(hr = session_presentation_object_get_rate(sink->object, direction, thin, fastest, &rate)))
3521 break;
3526 LeaveCriticalSection(&session->cs);
3528 if (SUCCEEDED(hr))
3529 *result = direction == MFRATE_FORWARD ? rate : -rate;
3531 return hr;
3534 static HRESULT session_is_presentation_rate_supported(struct media_session *session, BOOL thin, float rate,
3535 float *nearest_rate)
3537 IMFRateSupport *rate_support;
3538 struct media_source *source;
3539 struct media_sink *sink;
3540 float value = 0.0f, tmp;
3541 HRESULT hr = S_OK;
3542 DWORD flags;
3544 if (!nearest_rate) nearest_rate = &tmp;
3546 if (rate == 0.0f)
3548 *nearest_rate = 1.0f;
3549 return S_OK;
3552 EnterCriticalSection(&session->cs);
3554 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
3556 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3558 if (FAILED(hr = MFGetService(source->object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport,
3559 (void **)&rate_support)))
3561 value = 1.0f;
3562 break;
3565 value = rate;
3566 if (FAILED(hr = IMFRateSupport_IsRateSupported(rate_support, thin, rate, &value)))
3567 WARN("Source does not support rate %f, hr %#x.\n", rate, hr);
3568 IMFRateSupport_Release(rate_support);
3570 /* Only "first" source is considered. */
3571 break;
3574 if (SUCCEEDED(hr))
3576 /* For sinks only check if rate is supported, ignoring nearest values. */
3577 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
3579 flags = 0;
3580 if (FAILED(hr = IMFMediaSink_GetCharacteristics(sink->sink, &flags)))
3581 break;
3583 if (flags & MEDIASINK_RATELESS)
3584 continue;
3586 if (FAILED(MFGetService(sink->object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport,
3587 (void **)&rate_support)))
3588 continue;
3590 hr = IMFRateSupport_IsRateSupported(rate_support, thin, rate, NULL);
3591 IMFRateSupport_Release(rate_support);
3592 if (FAILED(hr))
3594 WARN("Sink %p does not support rate %f, hr %#x.\n", sink->sink, rate, hr);
3595 break;
3601 LeaveCriticalSection(&session->cs);
3603 *nearest_rate = value;
3605 return hr;
3608 static HRESULT WINAPI session_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
3609 BOOL thin, float *rate)
3611 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3613 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
3615 return session_get_presentation_rate(session, direction, thin, FALSE, rate);
3618 static HRESULT WINAPI session_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
3619 BOOL thin, float *rate)
3621 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3623 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
3625 return session_get_presentation_rate(session, direction, thin, TRUE, rate);
3628 static HRESULT WINAPI session_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
3629 float *nearest_supported_rate)
3631 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3633 TRACE("%p, %d, %f, %p.\n", iface, thin, rate, nearest_supported_rate);
3635 return session_is_presentation_rate_supported(session, thin, rate, nearest_supported_rate);
3638 static const IMFRateSupportVtbl session_rate_support_vtbl =
3640 session_rate_support_QueryInterface,
3641 session_rate_support_AddRef,
3642 session_rate_support_Release,
3643 session_rate_support_GetSlowestRate,
3644 session_rate_support_GetFastestRate,
3645 session_rate_support_IsRateSupported,
3648 static HRESULT WINAPI session_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj)
3650 struct media_session *session = impl_session_from_IMFRateControl(iface);
3651 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
3654 static ULONG WINAPI session_rate_control_AddRef(IMFRateControl *iface)
3656 struct media_session *session = impl_session_from_IMFRateControl(iface);
3657 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3660 static ULONG WINAPI session_rate_control_Release(IMFRateControl *iface)
3662 struct media_session *session = impl_session_from_IMFRateControl(iface);
3663 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3666 static HRESULT WINAPI session_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate)
3668 FIXME("%p, %d, %f.\n", iface, thin, rate);
3670 return E_NOTIMPL;
3673 static HRESULT WINAPI session_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
3675 struct media_session *session = impl_session_from_IMFRateControl(iface);
3677 TRACE("%p, %p, %p.\n", iface, thin, rate);
3679 return IMFRateControl_GetRate(session->clock_rate_control, thin, rate);
3682 static const IMFRateControlVtbl session_rate_control_vtbl =
3684 session_rate_control_QueryInterface,
3685 session_rate_control_AddRef,
3686 session_rate_control_Release,
3687 session_rate_control_SetRate,
3688 session_rate_control_GetRate,
3691 static HRESULT WINAPI node_attribute_editor_QueryInterface(IMFTopologyNodeAttributeEditor *iface,
3692 REFIID riid, void **obj)
3694 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
3696 if (IsEqualIID(riid, &IID_IMFTopologyNodeAttributeEditor) ||
3697 IsEqualIID(riid, &IID_IUnknown))
3699 *obj = iface;
3700 IMFTopologyNodeAttributeEditor_AddRef(iface);
3701 return S_OK;
3704 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
3705 *obj = NULL;
3706 return E_NOINTERFACE;
3709 static ULONG WINAPI node_attribute_editor_AddRef(IMFTopologyNodeAttributeEditor *iface)
3711 struct media_session *session = impl_session_from_IMFTopologyNodeAttributeEditor(iface);
3712 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3715 static ULONG WINAPI node_attribute_editor_Release(IMFTopologyNodeAttributeEditor *iface)
3717 struct media_session *session = impl_session_from_IMFTopologyNodeAttributeEditor(iface);
3718 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3721 static HRESULT WINAPI node_attribute_editor_UpdateNodeAttributes(IMFTopologyNodeAttributeEditor *iface,
3722 TOPOID id, DWORD count, MFTOPONODE_ATTRIBUTE_UPDATE *updates)
3724 FIXME("%p, %s, %u, %p.\n", iface, wine_dbgstr_longlong(id), count, updates);
3726 return E_NOTIMPL;
3729 static const IMFTopologyNodeAttributeEditorVtbl node_attribute_editor_vtbl =
3731 node_attribute_editor_QueryInterface,
3732 node_attribute_editor_AddRef,
3733 node_attribute_editor_Release,
3734 node_attribute_editor_UpdateNodeAttributes,
3737 /***********************************************************************
3738 * MFCreateMediaSession (mf.@)
3740 HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **session)
3742 BOOL without_quality_manager = FALSE;
3743 struct media_session *object;
3744 HRESULT hr;
3746 TRACE("%p, %p.\n", config, session);
3748 if (!(object = calloc(1, sizeof(*object))))
3749 return E_OUTOFMEMORY;
3751 object->IMFMediaSession_iface.lpVtbl = &mfmediasessionvtbl;
3752 object->IMFGetService_iface.lpVtbl = &session_get_service_vtbl;
3753 object->IMFRateSupport_iface.lpVtbl = &session_rate_support_vtbl;
3754 object->IMFRateControl_iface.lpVtbl = &session_rate_control_vtbl;
3755 object->IMFTopologyNodeAttributeEditor_iface.lpVtbl = &node_attribute_editor_vtbl;
3756 object->commands_callback.lpVtbl = &session_commands_callback_vtbl;
3757 object->events_callback.lpVtbl = &session_events_callback_vtbl;
3758 object->sink_finalizer_callback.lpVtbl = &session_sink_finalizer_callback_vtbl;
3759 object->refcount = 1;
3760 list_init(&object->topologies);
3761 list_init(&object->commands);
3762 list_init(&object->presentation.sources);
3763 list_init(&object->presentation.sinks);
3764 list_init(&object->presentation.nodes);
3765 InitializeCriticalSection(&object->cs);
3767 if (FAILED(hr = MFCreateTopology(&object->presentation.current_topology)))
3768 goto failed;
3770 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
3771 goto failed;
3773 if (FAILED(hr = MFCreatePresentationClock(&object->clock)))
3774 goto failed;
3776 if (FAILED(hr = MFCreateSystemTimeSource(&object->system_time_source)))
3777 goto failed;
3779 if (FAILED(hr = IMFPresentationClock_QueryInterface(object->clock, &IID_IMFRateControl,
3780 (void **)&object->clock_rate_control)))
3782 goto failed;
3785 if (config)
3787 GUID clsid;
3789 if (SUCCEEDED(IMFAttributes_GetGUID(config, &MF_SESSION_TOPOLOADER, &clsid)))
3791 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTopoLoader,
3792 (void **)&object->topo_loader)))
3794 WARN("Failed to create custom topology loader, hr %#x.\n", hr);
3798 if (SUCCEEDED(IMFAttributes_GetGUID(config, &MF_SESSION_QUALITY_MANAGER, &clsid)))
3800 if (!(without_quality_manager = IsEqualGUID(&clsid, &GUID_NULL)))
3802 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFQualityManager,
3803 (void **)&object->quality_manager)))
3805 WARN("Failed to create custom quality manager, hr %#x.\n", hr);
3811 if (!object->topo_loader && FAILED(hr = MFCreateTopoLoader(&object->topo_loader)))
3812 goto failed;
3814 if (!object->quality_manager && !without_quality_manager &&
3815 FAILED(hr = MFCreateStandardQualityManager(&object->quality_manager)))
3817 goto failed;
3820 if (object->quality_manager && FAILED(hr = IMFQualityManager_NotifyPresentationClock(object->quality_manager,
3821 object->clock)))
3823 goto failed;
3826 *session = &object->IMFMediaSession_iface;
3828 return S_OK;
3830 failed:
3831 IMFMediaSession_Release(&object->IMFMediaSession_iface);
3832 return hr;