winmm: Avoid explicitly casting the pointer returned from Heap(Re)Alloc.
[wine.git] / dlls / mf / session.c
blobb5b631fb00ad1be854aa280ef6c3b682e47124ac
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 SESSION_CMD_SET_RATE,
50 SESSION_CMD_SHUTDOWN,
53 struct session_op
55 IUnknown IUnknown_iface;
56 LONG refcount;
57 enum session_command command;
58 union
60 struct
62 DWORD flags;
63 IMFTopology *topology;
64 } set_topology;
65 struct
67 GUID time_format;
68 PROPVARIANT start_position;
69 } start;
70 struct
72 BOOL thin;
73 float rate;
74 } set_rate;
75 struct
77 IMFTopology *topology;
78 } notify_topology;
80 struct list entry;
83 struct queued_topology
85 struct list entry;
86 IMFTopology *topology;
87 MF_TOPOSTATUS status;
90 enum session_state
92 SESSION_STATE_STOPPED = 0,
93 SESSION_STATE_STARTING_SOURCES,
94 SESSION_STATE_PREROLLING_SINKS,
95 SESSION_STATE_STARTING_SINKS,
96 SESSION_STATE_STARTED,
97 SESSION_STATE_PAUSING_SINKS,
98 SESSION_STATE_PAUSING_SOURCES,
99 SESSION_STATE_PAUSED,
100 SESSION_STATE_STOPPING_SINKS,
101 SESSION_STATE_STOPPING_SOURCES,
102 SESSION_STATE_FINALIZING_SINKS,
103 SESSION_STATE_CLOSED,
104 SESSION_STATE_SHUT_DOWN,
107 enum object_state
109 OBJ_STATE_STOPPED = 0,
110 OBJ_STATE_STARTED,
111 OBJ_STATE_PAUSED,
112 OBJ_STATE_PREROLLED,
113 OBJ_STATE_INVALID,
116 enum media_source_flags
118 SOURCE_FLAG_END_OF_PRESENTATION = 0x1,
121 struct media_source
123 struct list entry;
124 union
126 IMFMediaSource *source;
127 IUnknown *object;
129 IMFPresentationDescriptor *pd;
130 enum object_state state;
131 unsigned int flags;
134 struct media_sink
136 struct list entry;
137 union
139 IMFMediaSink *sink;
140 IUnknown *object;
142 IMFMediaSinkPreroll *preroll;
143 IMFMediaEventGenerator *event_generator;
144 BOOL finalized;
147 struct sample
149 struct list entry;
150 IMFSample *sample;
153 struct transform_stream
155 struct list samples;
156 unsigned int requests;
157 unsigned int min_buffer_size;
158 BOOL draining;
161 enum topo_node_flags
163 TOPO_NODE_END_OF_STREAM = 0x1,
164 TOPO_NODE_SCRUB_SAMPLE_COMPLETE = 0x2,
167 struct topo_node
169 struct list entry;
170 struct media_session *session;
171 MF_TOPOLOGY_TYPE type;
172 TOPOID node_id;
173 IMFTopologyNode *node;
174 enum object_state state;
175 unsigned int flags;
176 union
178 IMFMediaStream *source_stream;
179 IMFStreamSink *sink_stream;
180 IMFTransform *transform;
181 IUnknown *object;
182 } object;
184 union
186 struct
188 IMFMediaSource *source;
189 DWORD stream_id;
190 } source;
191 struct
193 unsigned int requests;
194 IMFVideoSampleAllocatorNotify notify_cb;
195 IMFVideoSampleAllocator *allocator;
196 IMFVideoSampleAllocatorCallback *allocator_cb;
197 } sink;
198 struct
200 struct transform_stream *inputs;
201 DWORD *input_map;
202 unsigned int input_count;
203 unsigned int next_input;
205 struct transform_stream *outputs;
206 DWORD *output_map;
207 unsigned int output_count;
208 } transform;
209 } u;
212 enum presentation_flags
214 SESSION_FLAG_SOURCES_SUBSCRIBED = 0x1,
215 SESSION_FLAG_PRESENTATION_CLOCK_SET = 0x2,
216 SESSION_FLAG_FINALIZE_SINKS = 0x4,
217 SESSION_FLAG_NEEDS_PREROLL = 0x8,
218 SESSION_FLAG_END_OF_PRESENTATION = 0x10,
219 SESSION_FLAG_PENDING_RATE_CHANGE = 0x20,
220 SESSION_FLAG_PENDING_COMMAND = 0x40,
223 struct media_session
225 IMFMediaSession IMFMediaSession_iface;
226 IMFGetService IMFGetService_iface;
227 IMFRateSupport IMFRateSupport_iface;
228 IMFRateControl IMFRateControl_iface;
229 IMFTopologyNodeAttributeEditor IMFTopologyNodeAttributeEditor_iface;
230 IMFAsyncCallback commands_callback;
231 IMFAsyncCallback sa_ready_callback;
232 IMFAsyncCallback events_callback;
233 IMFAsyncCallback sink_finalizer_callback;
234 LONG refcount;
235 IMFMediaEventQueue *event_queue;
236 IMFPresentationClock *clock;
237 IMFPresentationTimeSource *system_time_source;
238 IMFRateControl *clock_rate_control;
239 IMFTopoLoader *topo_loader;
240 IMFQualityManager *quality_manager;
241 struct
243 IMFTopology *current_topology;
244 MF_TOPOSTATUS topo_status;
245 MFTIME clock_stop_time;
246 unsigned int flags;
247 struct list sources;
248 struct list sinks;
249 struct list nodes;
251 /* Latest Start() arguments. */
252 GUID time_format;
253 PROPVARIANT start_position;
254 /* Latest SetRate() arguments. */
255 BOOL thin;
256 float rate;
257 } presentation;
258 struct list topologies;
259 struct list commands;
260 enum session_state state;
261 DWORD caps;
262 CRITICAL_SECTION cs;
265 static inline struct media_session *impl_from_IMFMediaSession(IMFMediaSession *iface)
267 return CONTAINING_RECORD(iface, struct media_session, IMFMediaSession_iface);
270 static struct media_session *impl_from_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
272 return CONTAINING_RECORD(iface, struct media_session, commands_callback);
275 static struct media_session *impl_from_sa_ready_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
277 return CONTAINING_RECORD(iface, struct media_session, sa_ready_callback);
280 static struct media_session *impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
282 return CONTAINING_RECORD(iface, struct media_session, events_callback);
285 static struct media_session *impl_from_sink_finalizer_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
287 return CONTAINING_RECORD(iface, struct media_session, sink_finalizer_callback);
290 static struct media_session *impl_from_IMFGetService(IMFGetService *iface)
292 return CONTAINING_RECORD(iface, struct media_session, IMFGetService_iface);
295 static struct media_session *impl_session_from_IMFRateSupport(IMFRateSupport *iface)
297 return CONTAINING_RECORD(iface, struct media_session, IMFRateSupport_iface);
300 static struct media_session *impl_session_from_IMFRateControl(IMFRateControl *iface)
302 return CONTAINING_RECORD(iface, struct media_session, IMFRateControl_iface);
305 static struct media_session *impl_session_from_IMFTopologyNodeAttributeEditor(IMFTopologyNodeAttributeEditor *iface)
307 return CONTAINING_RECORD(iface, struct media_session, IMFTopologyNodeAttributeEditor_iface);
310 static struct session_op *impl_op_from_IUnknown(IUnknown *iface)
312 return CONTAINING_RECORD(iface, struct session_op, IUnknown_iface);
315 static struct topo_node *impl_node_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify *iface)
317 return CONTAINING_RECORD(iface, struct topo_node, u.sink.notify_cb);
320 /* IMFLocalMFTRegistration */
321 static HRESULT WINAPI local_mft_registration_QueryInterface(IMFLocalMFTRegistration *iface, REFIID riid, void **obj)
323 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
325 if (IsEqualIID(riid, &IID_IMFLocalMFTRegistration) ||
326 IsEqualIID(riid, &IID_IUnknown))
328 *obj = iface;
329 IMFLocalMFTRegistration_AddRef(iface);
330 return S_OK;
333 WARN("Unexpected %s.\n", debugstr_guid(riid));
334 *obj = NULL;
335 return E_NOINTERFACE;
338 static ULONG WINAPI local_mft_registration_AddRef(IMFLocalMFTRegistration *iface)
340 return 2;
343 static ULONG WINAPI local_mft_registration_Release(IMFLocalMFTRegistration *iface)
345 return 1;
348 static HRESULT WINAPI local_mft_registration_RegisterMFTs(IMFLocalMFTRegistration *iface, MFT_REGISTRATION_INFO *info,
349 DWORD count)
351 HRESULT hr = S_OK;
352 DWORD i;
354 TRACE("%p, %p, %lu.\n", iface, info, count);
356 for (i = 0; i < count; ++i)
358 if (FAILED(hr = MFTRegisterLocalByCLSID(&info[i].clsid, &info[i].guidCategory, info[i].pszName,
359 info[i].uiFlags, info[i].cInTypes, info[i].pInTypes, info[i].cOutTypes, info[i].pOutTypes)))
361 break;
365 return hr;
368 static const IMFLocalMFTRegistrationVtbl local_mft_registration_vtbl =
370 local_mft_registration_QueryInterface,
371 local_mft_registration_AddRef,
372 local_mft_registration_Release,
373 local_mft_registration_RegisterMFTs,
376 static IMFLocalMFTRegistration local_mft_registration = { &local_mft_registration_vtbl };
378 static HRESULT WINAPI session_op_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
380 if (IsEqualIID(riid, &IID_IUnknown))
382 *obj = iface;
383 IUnknown_AddRef(iface);
384 return S_OK;
387 *obj = NULL;
388 return E_NOINTERFACE;
391 static ULONG WINAPI session_op_AddRef(IUnknown *iface)
393 struct session_op *op = impl_op_from_IUnknown(iface);
394 ULONG refcount = InterlockedIncrement(&op->refcount);
396 TRACE("%p, refcount %lu.\n", iface, refcount);
398 return refcount;
401 static ULONG WINAPI session_op_Release(IUnknown *iface)
403 struct session_op *op = impl_op_from_IUnknown(iface);
404 ULONG refcount = InterlockedDecrement(&op->refcount);
406 TRACE("%p, refcount %lu.\n", iface, refcount);
408 if (!refcount)
410 switch (op->command)
412 case SESSION_CMD_SET_TOPOLOGY:
413 if (op->set_topology.topology)
414 IMFTopology_Release(op->set_topology.topology);
415 break;
416 case SESSION_CMD_START:
417 PropVariantClear(&op->start.start_position);
418 break;
419 default:
422 free(op);
425 return refcount;
428 static const IUnknownVtbl session_op_vtbl =
430 session_op_QueryInterface,
431 session_op_AddRef,
432 session_op_Release,
435 static HRESULT create_session_op(enum session_command command, struct session_op **ret)
437 struct session_op *op;
439 if (!(op = calloc(1, sizeof(*op))))
440 return E_OUTOFMEMORY;
442 op->IUnknown_iface.lpVtbl = &session_op_vtbl;
443 op->refcount = 1;
444 op->command = command;
446 *ret = op;
448 return S_OK;
451 static HRESULT session_is_shut_down(struct media_session *session)
453 return session->state == SESSION_STATE_SHUT_DOWN ? MF_E_SHUTDOWN : S_OK;
456 static HRESULT session_submit_command(struct media_session *session, struct session_op *op)
458 HRESULT hr;
460 TRACE("session %p, op %p, command %u.\n", session, op, op->command);
462 EnterCriticalSection(&session->cs);
463 if (SUCCEEDED(hr = session_is_shut_down(session)))
465 if (list_empty(&session->commands) && !(session->presentation.flags & SESSION_FLAG_PENDING_COMMAND))
466 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface);
467 if (op->command == SESSION_CMD_SHUTDOWN)
468 list_add_head(&session->commands, &op->entry);
469 else
470 list_add_tail(&session->commands, &op->entry);
471 IUnknown_AddRef(&op->IUnknown_iface);
473 LeaveCriticalSection(&session->cs);
475 return hr;
478 static HRESULT session_submit_simple_command(struct media_session *session, enum session_command command)
480 struct session_op *op;
481 HRESULT hr;
483 if (FAILED(hr = create_session_op(command, &op)))
484 return hr;
486 hr = session_submit_command(session, op);
487 IUnknown_Release(&op->IUnknown_iface);
488 return hr;
491 static void session_clear_queued_topologies(struct media_session *session)
493 struct queued_topology *ptr, *next;
495 LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &session->topologies, struct queued_topology, entry)
497 list_remove(&ptr->entry);
498 IMFTopology_Release(ptr->topology);
499 free(ptr);
503 static void session_set_topo_status(struct media_session *session, HRESULT status,
504 MF_TOPOSTATUS topo_status)
506 IMFMediaEvent *event;
507 PROPVARIANT param;
509 if (topo_status == MF_TOPOSTATUS_INVALID)
510 return;
512 if (list_empty(&session->topologies))
514 FIXME("Unexpectedly empty topology queue.\n");
515 return;
518 if (topo_status > session->presentation.topo_status)
520 struct queued_topology *topology = LIST_ENTRY(list_head(&session->topologies), struct queued_topology, entry);
522 param.vt = VT_UNKNOWN;
523 param.punkVal = (IUnknown *)topology->topology;
525 if (FAILED(MFCreateMediaEvent(MESessionTopologyStatus, &GUID_NULL, status, &param, &event)))
526 return;
528 session->presentation.topo_status = topo_status;
530 IMFMediaEvent_SetUINT32(event, &MF_EVENT_TOPOLOGY_STATUS, topo_status);
531 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
532 IMFMediaEvent_Release(event);
536 static HRESULT session_bind_output_nodes(IMFTopology *topology)
538 MF_TOPOLOGY_TYPE node_type;
539 IMFStreamSink *stream_sink;
540 IMFMediaSink *media_sink;
541 WORD node_count = 0, i;
542 IMFTopologyNode *node;
543 IMFActivate *activate;
544 UINT32 stream_id;
545 IUnknown *object;
546 HRESULT hr;
548 hr = IMFTopology_GetNodeCount(topology, &node_count);
550 for (i = 0; i < node_count; ++i)
552 if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
553 break;
555 if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type)) || node_type != MF_TOPOLOGY_OUTPUT_NODE)
557 IMFTopologyNode_Release(node);
558 continue;
561 if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object)))
563 stream_sink = NULL;
564 if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&stream_sink)))
566 if (SUCCEEDED(hr = IUnknown_QueryInterface(object, &IID_IMFActivate, (void **)&activate)))
568 if (SUCCEEDED(hr = IMFActivate_ActivateObject(activate, &IID_IMFMediaSink, (void **)&media_sink)))
570 if (FAILED(IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_STREAMID, &stream_id)))
571 stream_id = 0;
573 stream_sink = NULL;
574 if (FAILED(IMFMediaSink_GetStreamSinkById(media_sink, stream_id, &stream_sink)))
575 hr = IMFMediaSink_AddStreamSink(media_sink, stream_id, NULL, &stream_sink);
577 if (stream_sink)
578 hr = IMFTopologyNode_SetObject(node, (IUnknown *)stream_sink);
580 IMFMediaSink_Release(media_sink);
583 if (SUCCEEDED(hr))
584 IMFTopologyNode_SetUnknown(node, &_MF_TOPONODE_IMFActivate, (IUnknown *)activate);
586 IMFActivate_Release(activate);
590 if (stream_sink)
591 IMFStreamSink_Release(stream_sink);
592 IUnknown_Release(object);
595 IMFTopologyNode_Release(node);
598 return hr;
601 static HRESULT session_init_media_types(IMFTopology *topology)
603 MF_TOPOLOGY_TYPE node_type;
604 WORD node_count, i, j;
605 IMFTopologyNode *node;
606 IMFMediaType *type;
607 DWORD input_count;
608 HRESULT hr;
610 if (FAILED(hr = IMFTopology_GetNodeCount(topology, &node_count)))
611 return hr;
613 for (i = 0; i < node_count; ++i)
615 if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
616 break;
618 if (FAILED(hr = IMFTopologyNode_GetInputCount(node, &input_count))
619 || FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type))
620 || node_type != MF_TOPOLOGY_OUTPUT_NODE)
622 IMFTopologyNode_Release(node);
623 continue;
626 for (j = 0; j < input_count; ++j)
628 IMFMediaTypeHandler *handler;
629 IMFTopologyNode *up_node;
630 DWORD up_output;
632 if (SUCCEEDED(hr = IMFTopologyNode_GetInput(node, j, &up_node, &up_output)))
634 hr = topology_node_init_media_type(up_node, up_output, TRUE, &type);
635 IMFTopologyNode_Release(up_node);
637 if (FAILED(hr))
638 break;
640 if (SUCCEEDED(hr = topology_node_get_type_handler(node, j, FALSE, &handler)))
642 hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, type);
643 IMFMediaTypeHandler_Release(handler);
646 IMFMediaType_Release(type);
649 IMFTopologyNode_Release(node);
652 return hr;
655 static void session_set_caps(struct media_session *session, DWORD caps)
657 DWORD delta = session->caps ^ caps;
658 IMFMediaEvent *event;
660 /* Delta is documented to reflect rate value changes as well, but it's not clear what to compare
661 them to, since session always queries for current object rates. */
662 if (!delta)
663 return;
665 session->caps = caps;
667 if (FAILED(MFCreateMediaEvent(MESessionCapabilitiesChanged, &GUID_NULL, S_OK, NULL, &event)))
668 return;
670 IMFMediaEvent_SetUINT32(event, &MF_EVENT_SESSIONCAPS, caps);
671 IMFMediaEvent_SetUINT32(event, &MF_EVENT_SESSIONCAPS_DELTA, delta);
673 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
674 IMFMediaEvent_Release(event);
677 static HRESULT transform_stream_push_sample(struct transform_stream *stream, IMFSample *sample)
679 struct sample *entry;
681 if (!(entry = calloc(1, sizeof(*entry))))
682 return E_OUTOFMEMORY;
684 entry->sample = sample;
685 IMFSample_AddRef(entry->sample);
687 list_add_tail(&stream->samples, &entry->entry);
688 return S_OK;
691 static HRESULT transform_stream_pop_sample(struct transform_stream *stream, IMFSample **sample)
693 struct sample *entry;
694 struct list *ptr;
696 if (!(ptr = list_head(&stream->samples)))
697 return MF_E_TRANSFORM_NEED_MORE_INPUT;
699 entry = LIST_ENTRY(ptr, struct sample, entry);
700 list_remove(&entry->entry);
701 *sample = entry->sample;
702 free(entry);
703 return S_OK;
706 static void transform_stream_drop_samples(struct transform_stream *stream)
708 IMFSample *sample;
710 while (SUCCEEDED(transform_stream_pop_sample(stream, &sample)))
711 IMFSample_Release(sample);
714 static void release_topo_node(struct topo_node *node)
716 unsigned int i;
718 switch (node->type)
720 case MF_TOPOLOGY_SOURCESTREAM_NODE:
721 if (node->u.source.source)
722 IMFMediaSource_Release(node->u.source.source);
723 break;
724 case MF_TOPOLOGY_TRANSFORM_NODE:
725 for (i = 0; i < node->u.transform.input_count; ++i)
726 transform_stream_drop_samples(&node->u.transform.inputs[i]);
727 for (i = 0; i < node->u.transform.output_count; ++i)
728 transform_stream_drop_samples(&node->u.transform.outputs[i]);
729 free(node->u.transform.inputs);
730 free(node->u.transform.outputs);
731 free(node->u.transform.input_map);
732 free(node->u.transform.output_map);
733 break;
734 case MF_TOPOLOGY_OUTPUT_NODE:
735 if (node->u.sink.allocator)
736 IMFVideoSampleAllocator_Release(node->u.sink.allocator);
737 if (node->u.sink.allocator_cb)
739 IMFVideoSampleAllocatorCallback_SetCallback(node->u.sink.allocator_cb, NULL);
740 IMFVideoSampleAllocatorCallback_Release(node->u.sink.allocator_cb);
742 break;
743 default:
747 if (node->object.object)
748 IUnknown_Release(node->object.object);
749 if (node->node)
750 IMFTopologyNode_Release(node->node);
751 free(node);
754 static void session_shutdown_current_topology(struct media_session *session)
756 unsigned int shutdown, force_shutdown;
757 MF_TOPOLOGY_TYPE node_type;
758 IMFStreamSink *stream_sink;
759 IMFTopology *topology;
760 IMFTopologyNode *node;
761 IMFActivate *activate;
762 IMFMediaSink *sink;
763 WORD idx = 0;
764 HRESULT hr;
766 topology = session->presentation.current_topology;
767 force_shutdown = session->state == SESSION_STATE_SHUT_DOWN;
769 /* FIXME: should handle async MFTs, but these are not supported by the rest of the pipeline currently. */
771 while (SUCCEEDED(IMFTopology_GetNode(topology, idx++, &node)))
773 if (SUCCEEDED(IMFTopologyNode_GetNodeType(node, &node_type)) &&
774 node_type == MF_TOPOLOGY_OUTPUT_NODE)
776 shutdown = 1;
777 IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, &shutdown);
779 if (force_shutdown || shutdown)
781 if (SUCCEEDED(IMFTopologyNode_GetUnknown(node, &_MF_TOPONODE_IMFActivate, &IID_IMFActivate,
782 (void **)&activate)))
784 if (FAILED(hr = IMFActivate_ShutdownObject(activate)))
785 WARN("Failed to shut down activation object for the sink, hr %#lx.\n", hr);
786 IMFActivate_Release(activate);
788 else if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink)))
790 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink)))
792 IMFMediaSink_Shutdown(sink);
793 IMFMediaSink_Release(sink);
796 IMFStreamSink_Release(stream_sink);
801 IMFTopologyNode_Release(node);
805 static void session_clear_command_list(struct media_session *session)
807 struct session_op *op, *op2;
809 LIST_FOR_EACH_ENTRY_SAFE(op, op2, &session->commands, struct session_op, entry)
811 list_remove(&op->entry);
812 IUnknown_Release(&op->IUnknown_iface);
816 static void session_clear_presentation(struct media_session *session)
818 struct media_source *source, *source2;
819 struct media_sink *sink, *sink2;
820 struct topo_node *node, *node2;
822 session_shutdown_current_topology(session);
824 IMFTopology_Clear(session->presentation.current_topology);
825 session->presentation.topo_status = MF_TOPOSTATUS_INVALID;
826 session->presentation.flags = 0;
828 LIST_FOR_EACH_ENTRY_SAFE(source, source2, &session->presentation.sources, struct media_source, entry)
830 list_remove(&source->entry);
831 if (source->source)
832 IMFMediaSource_Release(source->source);
833 if (source->pd)
834 IMFPresentationDescriptor_Release(source->pd);
835 free(source);
838 LIST_FOR_EACH_ENTRY_SAFE(node, node2, &session->presentation.nodes, struct topo_node, entry)
840 list_remove(&node->entry);
841 release_topo_node(node);
844 LIST_FOR_EACH_ENTRY_SAFE(sink, sink2, &session->presentation.sinks, struct media_sink, entry)
846 list_remove(&sink->entry);
848 if (sink->sink)
849 IMFMediaSink_Release(sink->sink);
850 if (sink->preroll)
851 IMFMediaSinkPreroll_Release(sink->preroll);
852 if (sink->event_generator)
853 IMFMediaEventGenerator_Release(sink->event_generator);
854 free(sink);
858 static struct topo_node *session_get_node_by_id(const struct media_session *session, TOPOID id)
860 struct topo_node *node;
862 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
864 if (node->node_id == id)
865 return node;
868 return NULL;
871 static void session_command_complete(struct media_session *session)
873 struct session_op *op;
874 struct list *e;
876 session->presentation.flags &= ~SESSION_FLAG_PENDING_COMMAND;
878 /* Submit next command. */
879 if ((e = list_head(&session->commands)))
881 op = LIST_ENTRY(e, struct session_op, entry);
882 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface);
886 static void session_command_complete_with_event(struct media_session *session, MediaEventType event,
887 HRESULT status, const PROPVARIANT *param)
889 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, event, &GUID_NULL, status, param);
890 session_command_complete(session);
893 static HRESULT session_subscribe_sources(struct media_session *session)
895 struct media_source *source;
896 HRESULT hr = S_OK;
898 if (session->presentation.flags & SESSION_FLAG_SOURCES_SUBSCRIBED)
899 return hr;
901 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
903 if (FAILED(hr = IMFMediaSource_BeginGetEvent(source->source, &session->events_callback,
904 source->object)))
906 WARN("Failed to subscribe to source events, hr %#lx.\n", hr);
907 return hr;
911 session->presentation.flags |= SESSION_FLAG_SOURCES_SUBSCRIBED;
912 return hr;
915 static void session_start(struct media_session *session, const GUID *time_format, const PROPVARIANT *start_position)
917 struct media_source *source;
918 struct topo_node *topo_node;
919 HRESULT hr;
920 UINT i;
922 switch (session->state)
924 case SESSION_STATE_STOPPED:
926 /* Start request with no current topology. */
927 if (session->presentation.topo_status == MF_TOPOSTATUS_INVALID)
929 session_command_complete_with_event(session, MESessionStarted, MF_E_INVALIDREQUEST, NULL);
930 break;
933 /* fallthrough */
934 case SESSION_STATE_PAUSED:
936 session->presentation.time_format = *time_format;
937 session->presentation.start_position.vt = VT_EMPTY;
938 PropVariantCopy(&session->presentation.start_position, start_position);
940 if (FAILED(hr = session_subscribe_sources(session)))
942 session_command_complete_with_event(session, MESessionStarted, hr, NULL);
943 return;
946 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
948 if (FAILED(hr = IMFMediaSource_Start(source->source, source->pd, &GUID_NULL, start_position)))
950 WARN("Failed to start media source %p, hr %#lx.\n", source->source, hr);
951 session_command_complete_with_event(session, MESessionStarted, hr, NULL);
952 return;
956 LIST_FOR_EACH_ENTRY(topo_node, &session->presentation.nodes, struct topo_node, entry)
958 if (topo_node->type == MF_TOPOLOGY_TRANSFORM_NODE)
960 for (i = 0; i < topo_node->u.transform.input_count; i++)
962 struct transform_stream *stream = &topo_node->u.transform.inputs[i];
963 stream->draining = FALSE;
968 session->state = SESSION_STATE_STARTING_SOURCES;
969 break;
970 case SESSION_STATE_STARTED:
971 FIXME("Seeking is not implemented.\n");
972 session_command_complete(session);
973 break;
974 default:
975 session_command_complete_with_event(session, MESessionStarted, MF_E_INVALIDREQUEST, NULL);
976 break;
980 static void session_set_started(struct media_session *session)
982 struct media_source *source;
983 IMFMediaEvent *event;
984 unsigned int caps;
985 DWORD flags;
987 session->state = SESSION_STATE_STARTED;
989 caps = session->caps | MFSESSIONCAP_PAUSE;
991 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
993 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source->source, &flags)))
995 if (!(flags & MFMEDIASOURCE_CAN_PAUSE))
997 caps &= ~MFSESSIONCAP_PAUSE;
998 break;
1003 session_set_caps(session, caps);
1005 if (SUCCEEDED(MFCreateMediaEvent(MESessionStarted, &GUID_NULL, S_OK, NULL, &event)))
1007 IMFMediaEvent_SetUINT64(event, &MF_EVENT_PRESENTATION_TIME_OFFSET, 0);
1008 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
1009 IMFMediaEvent_Release(event);
1011 session_command_complete(session);
1014 static void session_set_paused(struct media_session *session, unsigned int state, HRESULT status)
1016 /* Failed event status could indicate a failure during normal transition to paused state,
1017 or an attempt to pause from invalid initial state. To finalize failed transition in the former case,
1018 state is still forced to PAUSED, otherwise previous state is retained. */
1019 if (state != ~0u) session->state = state;
1020 if (SUCCEEDED(status))
1021 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
1022 session_command_complete_with_event(session, MESessionPaused, status, NULL);
1025 static void session_set_closed(struct media_session *session, HRESULT status)
1027 session->state = SESSION_STATE_CLOSED;
1028 if (SUCCEEDED(status))
1029 session_set_caps(session, session->caps & ~(MFSESSIONCAP_START | MFSESSIONCAP_SEEK));
1030 session_command_complete_with_event(session, MESessionClosed, status, NULL);
1033 static void session_pause(struct media_session *session)
1035 unsigned int state = ~0u;
1036 HRESULT hr;
1038 switch (session->state)
1040 case SESSION_STATE_STARTED:
1042 /* Transition in two steps - pause the clock, wait for sinks, then pause sources. */
1043 if (SUCCEEDED(hr = IMFPresentationClock_Pause(session->clock)))
1044 session->state = SESSION_STATE_PAUSING_SINKS;
1045 state = SESSION_STATE_PAUSED;
1047 break;
1049 case SESSION_STATE_STOPPED:
1050 hr = MF_E_SESSION_PAUSEWHILESTOPPED;
1051 break;
1052 default:
1053 hr = MF_E_INVALIDREQUEST;
1056 if (FAILED(hr))
1057 session_set_paused(session, state, hr);
1060 static void session_clear_end_of_presentation(struct media_session *session)
1062 struct media_source *source;
1063 struct topo_node *node;
1065 session->presentation.flags &= ~SESSION_FLAG_END_OF_PRESENTATION;
1066 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
1068 source->flags &= ~SOURCE_FLAG_END_OF_PRESENTATION;
1070 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
1072 node->flags &= ~TOPO_NODE_END_OF_STREAM;
1074 session->presentation.topo_status = MF_TOPOSTATUS_READY;
1077 static void session_set_stopped(struct media_session *session, HRESULT status)
1079 MediaEventType event_type;
1080 IMFMediaEvent *event;
1082 session->state = SESSION_STATE_STOPPED;
1083 event_type = session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION ? MESessionEnded : MESessionStopped;
1085 if (SUCCEEDED(MFCreateMediaEvent(event_type, &GUID_NULL, status, NULL, &event)))
1087 IMFMediaEvent_SetUINT64(event, &MF_SESSION_APPROX_EVENT_OCCURRENCE_TIME, session->presentation.clock_stop_time);
1088 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
1089 IMFMediaEvent_Release(event);
1091 session_clear_end_of_presentation(session);
1092 session_command_complete(session);
1095 static void session_stop(struct media_session *session)
1097 HRESULT hr = MF_E_INVALIDREQUEST;
1099 switch (session->state)
1101 case SESSION_STATE_STARTED:
1102 case SESSION_STATE_PAUSED:
1104 /* Transition in two steps - stop the clock, wait for sinks, then stop sources. */
1105 IMFPresentationClock_GetTime(session->clock, &session->presentation.clock_stop_time);
1106 if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock)))
1107 session->state = SESSION_STATE_STOPPING_SINKS;
1108 else
1109 session_set_stopped(session, hr);
1111 break;
1112 case SESSION_STATE_STOPPED:
1113 hr = S_OK;
1114 /* fallthrough */
1115 default:
1116 session_command_complete_with_event(session, MESessionStopped, hr, NULL);
1117 break;
1121 static HRESULT session_finalize_sinks(struct media_session *session)
1123 IMFFinalizableMediaSink *fin_sink;
1124 BOOL sinks_finalized = TRUE;
1125 struct media_sink *sink;
1126 HRESULT hr = S_OK;
1128 session->presentation.flags &= ~SESSION_FLAG_FINALIZE_SINKS;
1129 session->state = SESSION_STATE_FINALIZING_SINKS;
1131 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
1133 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink->sink, &IID_IMFFinalizableMediaSink, (void **)&fin_sink)))
1135 hr = IMFFinalizableMediaSink_BeginFinalize(fin_sink, &session->sink_finalizer_callback,
1136 (IUnknown *)fin_sink);
1137 IMFFinalizableMediaSink_Release(fin_sink);
1138 if (FAILED(hr))
1139 break;
1140 sinks_finalized = FALSE;
1142 else
1143 sink->finalized = TRUE;
1146 if (sinks_finalized)
1147 session_set_closed(session, hr);
1149 return hr;
1152 static void session_close(struct media_session *session)
1154 HRESULT hr = S_OK;
1156 switch (session->state)
1158 case SESSION_STATE_STOPPED:
1159 hr = session_finalize_sinks(session);
1160 break;
1161 case SESSION_STATE_STARTED:
1162 case SESSION_STATE_PAUSED:
1163 session->presentation.flags |= SESSION_FLAG_FINALIZE_SINKS;
1164 if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock)))
1165 session->state = SESSION_STATE_STOPPING_SINKS;
1166 break;
1167 default:
1168 hr = MF_E_INVALIDREQUEST;
1169 break;
1172 session_clear_queued_topologies(session);
1173 if (FAILED(hr))
1174 session_set_closed(session, hr);
1177 static void session_clear_topologies(struct media_session *session)
1179 HRESULT hr = S_OK;
1181 if (session->state == SESSION_STATE_CLOSED)
1182 hr = MF_E_INVALIDREQUEST;
1183 else
1184 session_clear_queued_topologies(session);
1185 session_command_complete_with_event(session, MESessionTopologiesCleared, hr, NULL);
1188 static HRESULT session_is_presentation_rate_supported(struct media_session *session, BOOL thin, float rate,
1189 float *nearest_rate)
1191 IMFRateSupport *rate_support;
1192 struct media_source *source;
1193 struct media_sink *sink;
1194 float value = 0.0f, tmp;
1195 HRESULT hr = S_OK;
1196 DWORD flags;
1198 if (!nearest_rate) nearest_rate = &tmp;
1200 if (rate == 0.0f)
1202 *nearest_rate = 1.0f;
1203 return S_OK;
1206 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
1208 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
1210 if (FAILED(hr = MFGetService(source->object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport,
1211 (void **)&rate_support)))
1213 value = 1.0f;
1214 break;
1217 value = rate;
1218 if (FAILED(hr = IMFRateSupport_IsRateSupported(rate_support, thin, rate, &value)))
1219 WARN("Source does not support rate %f, hr %#lx.\n", rate, hr);
1220 IMFRateSupport_Release(rate_support);
1222 /* Only "first" source is considered. */
1223 break;
1226 if (SUCCEEDED(hr))
1228 /* For sinks only check if rate is supported, ignoring nearest values. */
1229 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
1231 flags = 0;
1232 if (FAILED(hr = IMFMediaSink_GetCharacteristics(sink->sink, &flags)))
1233 break;
1235 if (flags & MEDIASINK_RATELESS)
1236 continue;
1238 if (FAILED(MFGetService(sink->object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport,
1239 (void **)&rate_support)))
1240 continue;
1242 hr = IMFRateSupport_IsRateSupported(rate_support, thin, rate, NULL);
1243 IMFRateSupport_Release(rate_support);
1244 if (FAILED(hr))
1246 WARN("Sink %p does not support rate %f, hr %#lx.\n", sink->sink, rate, hr);
1247 break;
1253 *nearest_rate = value;
1255 return hr;
1258 static void session_set_consumed_clock(IUnknown *object, IMFPresentationClock *clock)
1260 IMFClockConsumer *consumer;
1262 if (SUCCEEDED(IUnknown_QueryInterface(object, &IID_IMFClockConsumer, (void **)&consumer)))
1264 IMFClockConsumer_SetPresentationClock(consumer, clock);
1265 IMFClockConsumer_Release(consumer);
1269 static void session_set_presentation_clock(struct media_session *session)
1271 IMFPresentationTimeSource *time_source = NULL;
1272 struct media_source *source;
1273 struct media_sink *sink;
1274 struct topo_node *node;
1275 HRESULT hr;
1277 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
1279 if (node->type == MF_TOPOLOGY_TRANSFORM_NODE)
1280 IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
1283 if (!(session->presentation.flags & SESSION_FLAG_PRESENTATION_CLOCK_SET))
1285 /* Attempt to get time source from the sinks. */
1286 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
1288 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink->sink, &IID_IMFPresentationTimeSource,
1289 (void **)&time_source)))
1290 break;
1293 if (time_source)
1295 hr = IMFPresentationClock_SetTimeSource(session->clock, time_source);
1296 IMFPresentationTimeSource_Release(time_source);
1298 else
1299 hr = IMFPresentationClock_SetTimeSource(session->clock, session->system_time_source);
1301 if (FAILED(hr))
1302 WARN("Failed to set time source, hr %#lx.\n", hr);
1304 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
1306 if (node->type != MF_TOPOLOGY_OUTPUT_NODE)
1307 continue;
1309 if (FAILED(hr = IMFStreamSink_BeginGetEvent(node->object.sink_stream, &session->events_callback,
1310 node->object.object)))
1312 WARN("Failed to subscribe to stream sink events, hr %#lx.\n", hr);
1316 /* Set clock for all topology nodes. */
1317 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
1319 session_set_consumed_clock(source->object, session->clock);
1322 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
1324 if (sink->event_generator && FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(sink->event_generator,
1325 &session->events_callback, (IUnknown *)sink->event_generator)))
1327 WARN("Failed to subscribe to sink events, hr %#lx.\n", hr);
1330 if (FAILED(hr = IMFMediaSink_SetPresentationClock(sink->sink, session->clock)))
1331 WARN("Failed to set presentation clock for the sink, hr %#lx.\n", hr);
1334 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
1336 if (node->type != MF_TOPOLOGY_TRANSFORM_NODE)
1337 continue;
1339 session_set_consumed_clock(node->object.object, session->clock);
1342 session->presentation.flags |= SESSION_FLAG_PRESENTATION_CLOCK_SET;
1346 static void session_set_rate(struct media_session *session, BOOL thin, float rate)
1348 IMFRateControl *rate_control;
1349 struct media_source *source;
1350 float clock_rate = 0.0f;
1351 PROPVARIANT param;
1352 HRESULT hr;
1354 hr = session_is_presentation_rate_supported(session, thin, rate, NULL);
1356 if (SUCCEEDED(hr))
1357 hr = IMFRateControl_GetRate(session->clock_rate_control, NULL, &clock_rate);
1359 if (SUCCEEDED(hr) && (rate != clock_rate) && SUCCEEDED(hr = session_subscribe_sources(session)))
1361 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
1363 if (SUCCEEDED(hr = MFGetService(source->object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateControl,
1364 (void **)&rate_control)))
1366 hr = IMFRateControl_SetRate(rate_control, thin, rate);
1367 IMFRateControl_Release(rate_control);
1368 if (SUCCEEDED(hr))
1370 session->presentation.flags |= SESSION_FLAG_PENDING_RATE_CHANGE;
1371 session->presentation.rate = rate;
1372 return;
1376 break;
1380 param.vt = VT_R4;
1381 param.fltVal = rate;
1382 session_command_complete_with_event(session, MESessionRateChanged, hr, SUCCEEDED(hr) ? &param : NULL);
1385 static void session_complete_rate_change(struct media_session *session)
1387 PROPVARIANT param;
1388 HRESULT hr;
1390 if (!(session->presentation.flags & SESSION_FLAG_PENDING_RATE_CHANGE))
1391 return;
1393 session->presentation.flags &= ~SESSION_FLAG_PENDING_RATE_CHANGE;
1394 session_set_presentation_clock(session);
1396 hr = IMFRateControl_SetRate(session->clock_rate_control, session->presentation.thin,
1397 session->presentation.rate);
1399 param.vt = VT_R4;
1400 param.fltVal = session->presentation.rate;
1402 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionRateChanged, &GUID_NULL, hr,
1403 SUCCEEDED(hr) ? &param : NULL);
1404 session_command_complete(session);
1407 static struct media_source *session_get_media_source(struct media_session *session, IMFMediaSource *source)
1409 struct media_source *cur;
1411 LIST_FOR_EACH_ENTRY(cur, &session->presentation.sources, struct media_source, entry)
1413 if (source == cur->source)
1414 return cur;
1417 return NULL;
1420 static void session_release_media_source(struct media_source *source)
1422 IMFMediaSource_Release(source->source);
1423 if (source->pd)
1424 IMFPresentationDescriptor_Release(source->pd);
1425 free(source);
1428 static HRESULT session_add_media_source(struct media_session *session, IMFTopologyNode *node, IMFMediaSource *source)
1430 struct media_source *media_source;
1431 HRESULT hr;
1433 if (session_get_media_source(session, source))
1434 return S_FALSE;
1436 if (!(media_source = calloc(1, sizeof(*media_source))))
1437 return E_OUTOFMEMORY;
1439 media_source->source = source;
1440 IMFMediaSource_AddRef(media_source->source);
1442 hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, &IID_IMFPresentationDescriptor,
1443 (void **)&media_source->pd);
1445 if (SUCCEEDED(hr))
1446 list_add_tail(&session->presentation.sources, &media_source->entry);
1447 else
1448 session_release_media_source(media_source);
1450 return hr;
1453 static void session_raise_topology_set(struct media_session *session, IMFTopology *topology, HRESULT status)
1455 PROPVARIANT param;
1457 param.vt = topology ? VT_UNKNOWN : VT_EMPTY;
1458 param.punkVal = (IUnknown *)topology;
1460 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologySet, &GUID_NULL, status, &param);
1463 static DWORD session_get_object_rate_caps(IUnknown *object)
1465 IMFRateSupport *rate_support;
1466 DWORD caps = 0;
1467 float rate;
1469 if (SUCCEEDED(MFGetService(object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support)))
1471 rate = 0.0f;
1472 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support, MFRATE_FORWARD, TRUE, &rate)) && rate != 0.0f)
1473 caps |= MFSESSIONCAP_RATE_FORWARD;
1475 rate = 0.0f;
1476 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support, MFRATE_REVERSE, TRUE, &rate)) && rate != 0.0f)
1477 caps |= MFSESSIONCAP_RATE_REVERSE;
1479 IMFRateSupport_Release(rate_support);
1482 return caps;
1485 static HRESULT session_add_media_sink(struct media_session *session, IMFTopologyNode *node, IMFMediaSink *sink)
1487 struct media_sink *media_sink;
1488 unsigned int disable_preroll = 0;
1489 DWORD flags;
1491 LIST_FOR_EACH_ENTRY(media_sink, &session->presentation.sinks, struct media_sink, entry)
1493 if (sink == media_sink->sink)
1494 return S_FALSE;
1497 if (!(media_sink = calloc(1, sizeof(*media_sink))))
1498 return E_OUTOFMEMORY;
1500 media_sink->sink = sink;
1501 IMFMediaSink_AddRef(media_sink->sink);
1503 IMFMediaSink_QueryInterface(media_sink->sink, &IID_IMFMediaEventGenerator, (void **)&media_sink->event_generator);
1505 IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_DISABLE_PREROLL, &disable_preroll);
1506 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink, &flags)) && flags & MEDIASINK_CAN_PREROLL && !disable_preroll)
1508 if (SUCCEEDED(IMFMediaSink_QueryInterface(media_sink->sink, &IID_IMFMediaSinkPreroll, (void **)&media_sink->preroll)))
1509 session->presentation.flags |= SESSION_FLAG_NEEDS_PREROLL;
1512 list_add_tail(&session->presentation.sinks, &media_sink->entry);
1514 return S_OK;
1517 static DWORD transform_node_get_stream_id(struct topo_node *node, BOOL output, unsigned int index)
1519 DWORD *map = output ? node->u.transform.output_map : node->u.transform.input_map;
1520 return map ? map[index] : index;
1523 static HRESULT session_set_transform_stream_info(struct topo_node *node)
1525 DWORD *input_map = NULL, *output_map = NULL;
1526 DWORD i, input_count, output_count;
1527 struct transform_stream *streams;
1528 unsigned int block_alignment;
1529 IMFMediaType *media_type;
1530 UINT32 bytes_per_second;
1531 GUID major = { 0 };
1532 HRESULT hr;
1534 hr = IMFTransform_GetStreamCount(node->object.transform, &input_count, &output_count);
1535 if (SUCCEEDED(hr) && (input_count > 1 || output_count > 1))
1537 input_map = calloc(input_count, sizeof(*input_map));
1538 output_map = calloc(output_count, sizeof(*output_map));
1539 if (FAILED(IMFTransform_GetStreamIDs(node->object.transform, input_count, input_map,
1540 output_count, output_map)))
1542 /* Assume sequential identifiers. */
1543 free(input_map);
1544 free(output_map);
1545 input_map = output_map = NULL;
1549 if (SUCCEEDED(hr))
1551 node->u.transform.input_map = input_map;
1552 node->u.transform.output_map = output_map;
1554 streams = calloc(input_count, sizeof(*streams));
1555 for (i = 0; i < input_count; ++i)
1556 list_init(&streams[i].samples);
1557 node->u.transform.inputs = streams;
1558 node->u.transform.input_count = input_count;
1560 streams = calloc(output_count, sizeof(*streams));
1561 for (i = 0; i < output_count; ++i)
1563 list_init(&streams[i].samples);
1565 if (SUCCEEDED(IMFTransform_GetOutputCurrentType(node->object.transform,
1566 transform_node_get_stream_id(node, TRUE, i), &media_type)))
1568 if (SUCCEEDED(IMFMediaType_GetMajorType(media_type, &major)) && IsEqualGUID(&major, &MFMediaType_Audio)
1569 && SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment)))
1571 streams[i].min_buffer_size = block_alignment;
1572 if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &bytes_per_second)))
1573 streams[i].min_buffer_size = max(streams[i].min_buffer_size, bytes_per_second);
1575 IMFMediaType_Release(media_type);
1578 node->u.transform.outputs = streams;
1579 node->u.transform.output_count = output_count;
1582 return hr;
1585 static HRESULT session_get_stream_sink_type(IMFStreamSink *sink, IMFMediaType **media_type)
1587 IMFMediaTypeHandler *handler;
1588 HRESULT hr;
1590 if (SUCCEEDED(hr = IMFStreamSink_GetMediaTypeHandler(sink, &handler)))
1592 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, media_type);
1593 IMFMediaTypeHandler_Release(handler);
1596 return hr;
1599 static HRESULT WINAPI node_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify *iface,
1600 REFIID riid, void **obj)
1602 if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorNotify) ||
1603 IsEqualIID(riid, &IID_IUnknown))
1605 *obj = iface;
1606 IMFVideoSampleAllocatorNotify_AddRef(iface);
1607 return S_OK;
1610 *obj = NULL;
1611 return E_NOINTERFACE;
1614 static ULONG WINAPI node_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify *iface)
1616 return 2;
1619 static ULONG WINAPI node_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify *iface)
1621 return 1;
1624 static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output);
1626 static HRESULT WINAPI node_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify *iface)
1628 struct topo_node *topo_node = impl_node_from_IMFVideoSampleAllocatorNotify(iface);
1629 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &topo_node->session->sa_ready_callback, (IUnknown *)iface);
1630 return S_OK;
1633 static const IMFVideoSampleAllocatorNotifyVtbl node_sample_allocator_cb_vtbl =
1635 node_sample_allocator_cb_QueryInterface,
1636 node_sample_allocator_cb_AddRef,
1637 node_sample_allocator_cb_Release,
1638 node_sample_allocator_cb_NotifyRelease,
1641 static HRESULT session_append_node(struct media_session *session, IMFTopologyNode *node)
1643 struct topo_node *topo_node;
1644 IMFMediaSink *media_sink;
1645 IMFMediaType *media_type;
1646 IMFStreamDescriptor *sd;
1647 HRESULT hr = S_OK;
1649 if (!(topo_node = calloc(1, sizeof(*topo_node))))
1650 return E_OUTOFMEMORY;
1652 IMFTopologyNode_GetNodeType(node, &topo_node->type);
1653 IMFTopologyNode_GetTopoNodeID(node, &topo_node->node_id);
1654 topo_node->node = node;
1655 IMFTopologyNode_AddRef(topo_node->node);
1656 topo_node->session = session;
1658 switch (topo_node->type)
1660 case MF_TOPOLOGY_OUTPUT_NODE:
1661 topo_node->u.sink.notify_cb.lpVtbl = &node_sample_allocator_cb_vtbl;
1663 if (FAILED(hr = topology_node_get_object(node, &IID_IMFStreamSink, (void **)&topo_node->object.object)))
1665 WARN("Failed to get stream sink interface, hr %#lx.\n", hr);
1666 break;
1669 if (FAILED(hr = IMFStreamSink_GetMediaSink(topo_node->object.sink_stream, &media_sink)))
1670 break;
1672 if (SUCCEEDED(hr = session_add_media_sink(session, node, media_sink)))
1674 if (SUCCEEDED(session_get_stream_sink_type(topo_node->object.sink_stream, &media_type)))
1676 if (SUCCEEDED(MFGetService(topo_node->object.object, &MR_VIDEO_ACCELERATION_SERVICE,
1677 &IID_IMFVideoSampleAllocator, (void **)&topo_node->u.sink.allocator)))
1679 if (FAILED(hr = IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node->u.sink.allocator,
1680 2, media_type)))
1682 WARN("Failed to initialize sample allocator for the stream, hr %#lx.\n", hr);
1684 IMFVideoSampleAllocator_QueryInterface(topo_node->u.sink.allocator,
1685 &IID_IMFVideoSampleAllocatorCallback, (void **)&topo_node->u.sink.allocator_cb);
1686 IMFVideoSampleAllocatorCallback_SetCallback(topo_node->u.sink.allocator_cb,
1687 &topo_node->u.sink.notify_cb);
1689 IMFMediaType_Release(media_type);
1692 IMFMediaSink_Release(media_sink);
1694 break;
1695 case MF_TOPOLOGY_SOURCESTREAM_NODE:
1696 if (FAILED(IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_SOURCE, &IID_IMFMediaSource,
1697 (void **)&topo_node->u.source.source)))
1699 WARN("Missing MF_TOPONODE_SOURCE, hr %#lx.\n", hr);
1700 break;
1703 if (FAILED(hr = session_add_media_source(session, node, topo_node->u.source.source)))
1704 break;
1706 if (FAILED(hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR,
1707 &IID_IMFStreamDescriptor, (void **)&sd)))
1709 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#lx.\n", hr);
1710 break;
1713 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &topo_node->u.source.stream_id);
1714 IMFStreamDescriptor_Release(sd);
1716 break;
1717 case MF_TOPOLOGY_TRANSFORM_NODE:
1719 if (SUCCEEDED(hr = topology_node_get_object(node, &IID_IMFTransform, (void **)&topo_node->object.transform)))
1721 hr = session_set_transform_stream_info(topo_node);
1723 else
1724 WARN("Failed to get IMFTransform for MFT node, hr %#lx.\n", hr);
1726 break;
1727 case MF_TOPOLOGY_TEE_NODE:
1728 FIXME("Unsupported node type %d.\n", topo_node->type);
1730 break;
1731 default:
1735 if (SUCCEEDED(hr))
1736 list_add_tail(&session->presentation.nodes, &topo_node->entry);
1737 else
1738 release_topo_node(topo_node);
1740 return hr;
1743 static HRESULT session_collect_nodes(struct media_session *session)
1745 IMFTopology *topology = session->presentation.current_topology;
1746 IMFTopologyNode *node;
1747 WORD i, count = 0;
1748 HRESULT hr;
1750 if (!list_empty(&session->presentation.nodes))
1751 return S_OK;
1753 if (FAILED(hr = IMFTopology_GetNodeCount(topology, &count)))
1754 return hr;
1756 for (i = 0; i < count; ++i)
1758 if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
1760 WARN("Failed to get node %u.\n", i);
1761 break;
1764 hr = session_append_node(session, node);
1765 IMFTopologyNode_Release(node);
1766 if (FAILED(hr))
1768 WARN("Failed to add node %u.\n", i);
1769 break;
1773 return hr;
1776 static HRESULT session_set_current_topology(struct media_session *session, IMFTopology *topology)
1778 struct media_source *source;
1779 DWORD caps, object_flags;
1780 struct media_sink *sink;
1781 struct topo_node *node;
1782 IMFMediaEvent *event;
1783 HRESULT hr;
1785 if (FAILED(hr = IMFTopology_CloneFrom(session->presentation.current_topology, topology)))
1787 WARN("Failed to clone topology, hr %#lx.\n", hr);
1788 return hr;
1791 session_collect_nodes(session);
1793 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
1795 if (node->type == MF_TOPOLOGY_TRANSFORM_NODE)
1797 if (FAILED(hr = IMFTransform_ProcessMessage(node->object.transform,
1798 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0)))
1799 return hr;
1803 /* FIXME: attributes are all zero for now */
1804 if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime, &GUID_NULL, S_OK, NULL, &event)))
1806 IMFMediaEvent_SetUINT64(event, &MF_EVENT_START_PRESENTATION_TIME, 0);
1807 IMFMediaEvent_SetUINT64(event, &MF_EVENT_PRESENTATION_TIME_OFFSET, 0);
1808 IMFMediaEvent_SetUINT64(event, &MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT, 0);
1810 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
1811 IMFMediaEvent_Release(event);
1814 /* Update session caps. */
1815 caps = MFSESSIONCAP_START | MFSESSIONCAP_SEEK | MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE |
1816 MFSESSIONCAP_DOES_NOT_USE_NETWORK;
1818 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
1820 if (!caps)
1821 break;
1823 object_flags = 0;
1824 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source->source, &object_flags)))
1826 if (!(object_flags & MFMEDIASOURCE_DOES_NOT_USE_NETWORK))
1827 caps &= ~MFSESSIONCAP_DOES_NOT_USE_NETWORK;
1828 if (!(object_flags & MFMEDIASOURCE_CAN_SEEK))
1829 caps &= ~MFSESSIONCAP_SEEK;
1832 /* Mask unsupported rate caps. */
1834 caps &= session_get_object_rate_caps(source->object)
1835 | ~(MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE);
1838 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
1840 if (!caps)
1841 break;
1843 object_flags = 0;
1844 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink->sink, &object_flags)))
1846 if (!(object_flags & MEDIASINK_RATELESS))
1847 caps &= session_get_object_rate_caps(sink->object)
1848 | ~(MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE);
1852 session_set_caps(session, caps);
1854 return S_OK;
1857 static void session_set_topology(struct media_session *session, DWORD flags, IMFTopology *topology)
1859 IMFTopology *resolved_topology = NULL;
1860 HRESULT hr = S_OK;
1862 /* Resolve unless claimed to be full. */
1863 if (!(flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT) && topology)
1865 if (!(flags & MFSESSION_SETTOPOLOGY_NORESOLUTION))
1867 hr = session_bind_output_nodes(topology);
1869 if (SUCCEEDED(hr))
1870 hr = IMFTopoLoader_Load(session->topo_loader, topology, &resolved_topology, NULL /* FIXME? */);
1871 if (SUCCEEDED(hr))
1872 hr = session_init_media_types(resolved_topology);
1874 if (SUCCEEDED(hr))
1876 topology = resolved_topology;
1881 if (flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT)
1883 if ((topology && topology == session->presentation.current_topology) || !topology)
1885 /* FIXME: stop current topology, queue next one. */
1886 session_clear_presentation(session);
1888 else
1889 hr = S_FALSE;
1891 topology = NULL;
1893 else if (topology && flags & MFSESSION_SETTOPOLOGY_IMMEDIATE)
1895 session_clear_queued_topologies(session);
1896 session_clear_presentation(session);
1899 session_raise_topology_set(session, topology, hr);
1901 /* With no current topology set it right away, otherwise queue. */
1902 if (topology)
1904 struct queued_topology *queued_topology;
1906 if ((queued_topology = calloc(1, sizeof(*queued_topology))))
1908 queued_topology->topology = topology;
1909 IMFTopology_AddRef(queued_topology->topology);
1911 list_add_tail(&session->topologies, &queued_topology->entry);
1914 if (session->presentation.topo_status == MF_TOPOSTATUS_INVALID)
1916 hr = session_set_current_topology(session, topology);
1917 session_set_topo_status(session, hr, MF_TOPOSTATUS_READY);
1918 if (session->quality_manager)
1919 IMFQualityManager_NotifyTopology(session->quality_manager, topology);
1923 if (resolved_topology)
1924 IMFTopology_Release(resolved_topology);
1927 static HRESULT WINAPI mfsession_QueryInterface(IMFMediaSession *iface, REFIID riid, void **out)
1929 struct media_session *session = impl_from_IMFMediaSession(iface);
1931 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1933 *out = NULL;
1935 if (IsEqualIID(riid, &IID_IMFMediaSession) ||
1936 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
1937 IsEqualIID(riid, &IID_IUnknown))
1939 *out = &session->IMFMediaSession_iface;
1941 else if (IsEqualIID(riid, &IID_IMFGetService))
1943 *out = &session->IMFGetService_iface;
1945 else if (IsEqualIID(riid, &IID_IMFRateSupport))
1947 *out = &session->IMFRateSupport_iface;
1949 else if (IsEqualIID(riid, &IID_IMFRateControl))
1951 *out = &session->IMFRateControl_iface;
1954 if (*out)
1956 IMFMediaSession_AddRef(iface);
1957 return S_OK;
1960 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1961 return E_NOINTERFACE;
1964 static ULONG WINAPI mfsession_AddRef(IMFMediaSession *iface)
1966 struct media_session *session = impl_from_IMFMediaSession(iface);
1967 ULONG refcount = InterlockedIncrement(&session->refcount);
1969 TRACE("%p, refcount %lu.\n", iface, refcount);
1971 return refcount;
1974 static ULONG WINAPI mfsession_Release(IMFMediaSession *iface)
1976 struct media_session *session = impl_from_IMFMediaSession(iface);
1977 ULONG refcount = InterlockedDecrement(&session->refcount);
1979 TRACE("%p, refcount %lu.\n", iface, refcount);
1981 if (!refcount)
1983 session_clear_queued_topologies(session);
1984 session_clear_presentation(session);
1985 session_clear_command_list(session);
1986 if (session->presentation.current_topology)
1987 IMFTopology_Release(session->presentation.current_topology);
1988 if (session->event_queue)
1989 IMFMediaEventQueue_Release(session->event_queue);
1990 if (session->clock)
1991 IMFPresentationClock_Release(session->clock);
1992 if (session->system_time_source)
1993 IMFPresentationTimeSource_Release(session->system_time_source);
1994 if (session->clock_rate_control)
1995 IMFRateControl_Release(session->clock_rate_control);
1996 if (session->topo_loader)
1997 IMFTopoLoader_Release(session->topo_loader);
1998 if (session->quality_manager)
1999 IMFQualityManager_Release(session->quality_manager);
2000 DeleteCriticalSection(&session->cs);
2001 free(session);
2004 return refcount;
2007 static HRESULT WINAPI mfsession_GetEvent(IMFMediaSession *iface, DWORD flags, IMFMediaEvent **event)
2009 struct media_session *session = impl_from_IMFMediaSession(iface);
2011 TRACE("%p, %#lx, %p.\n", iface, flags, event);
2013 return IMFMediaEventQueue_GetEvent(session->event_queue, flags, event);
2016 static HRESULT WINAPI mfsession_BeginGetEvent(IMFMediaSession *iface, IMFAsyncCallback *callback, IUnknown *state)
2018 struct media_session *session = impl_from_IMFMediaSession(iface);
2020 TRACE("%p, %p, %p.\n", iface, callback, state);
2022 return IMFMediaEventQueue_BeginGetEvent(session->event_queue, callback, state);
2025 static HRESULT WINAPI mfsession_EndGetEvent(IMFMediaSession *iface, IMFAsyncResult *result, IMFMediaEvent **event)
2027 struct media_session *session = impl_from_IMFMediaSession(iface);
2029 TRACE("%p, %p, %p.\n", iface, result, event);
2031 return IMFMediaEventQueue_EndGetEvent(session->event_queue, result, event);
2034 static HRESULT WINAPI mfsession_QueueEvent(IMFMediaSession *iface, MediaEventType event_type, REFGUID ext_type,
2035 HRESULT hr, const PROPVARIANT *value)
2037 struct media_session *session = impl_from_IMFMediaSession(iface);
2039 TRACE("%p, %ld, %s, %#lx, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
2041 return IMFMediaEventQueue_QueueEventParamVar(session->event_queue, event_type, ext_type, hr, value);
2044 static HRESULT session_check_stream_descriptor(IMFPresentationDescriptor *pd, IMFStreamDescriptor *sd)
2046 IMFStreamDescriptor *selected_sd;
2047 DWORD i, count;
2048 BOOL selected;
2049 HRESULT hr;
2051 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(pd, &count)))
2053 WARN("Failed to get stream descriptor count, hr %#lx.\n", hr);
2054 return MF_E_TOPO_STREAM_DESCRIPTOR_NOT_SELECTED;
2057 for (i = 0; i < count; ++i)
2059 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, i,
2060 &selected, &selected_sd)))
2062 WARN("Failed to get stream descriptor %lu, hr %#lx.\n", i, hr);
2063 return MF_E_TOPO_STREAM_DESCRIPTOR_NOT_SELECTED;
2065 IMFStreamDescriptor_Release(selected_sd);
2067 if (selected_sd == sd)
2069 if (selected)
2070 return S_OK;
2072 WARN("Presentation descriptor %p stream %p is not selected.\n", pd, sd);
2073 return MF_E_TOPO_STREAM_DESCRIPTOR_NOT_SELECTED;
2077 WARN("Failed to find stream descriptor %lu, hr %#lx.\n", i, hr);
2078 return MF_E_TOPO_STREAM_DESCRIPTOR_NOT_SELECTED;
2081 static HRESULT session_check_topology(IMFTopology *topology)
2083 MF_TOPOLOGY_TYPE node_type;
2084 IMFTopologyNode *node;
2085 WORD node_count, i;
2086 HRESULT hr;
2088 if (!topology)
2089 return S_OK;
2091 if (FAILED(IMFTopology_GetNodeCount(topology, &node_count))
2092 || node_count == 0)
2093 return E_INVALIDARG;
2095 for (i = 0; i < node_count; ++i)
2097 if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
2098 break;
2100 if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type)))
2102 IMFTopologyNode_Release(node);
2103 break;
2106 switch (node_type)
2108 case MF_TOPOLOGY_SOURCESTREAM_NODE:
2110 IMFPresentationDescriptor *pd;
2111 IMFStreamDescriptor *sd;
2112 IMFMediaSource *source;
2114 if (FAILED(hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_SOURCE, &IID_IMFMediaSource,
2115 (void **)&source)))
2117 WARN("Missing MF_TOPONODE_SOURCE, hr %#lx.\n", hr);
2118 IMFTopologyNode_Release(node);
2119 return MF_E_TOPO_MISSING_SOURCE;
2121 IMFMediaSource_Release(source);
2123 if (FAILED(hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR,
2124 &IID_IMFPresentationDescriptor, (void **)&pd)))
2126 WARN("Missing MF_TOPONODE_PRESENTATION_DESCRIPTOR, hr %#lx.\n", hr);
2127 IMFTopologyNode_Release(node);
2128 return MF_E_TOPO_MISSING_PRESENTATION_DESCRIPTOR;
2131 if (FAILED(hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR,
2132 &IID_IMFStreamDescriptor, (void **)&sd)))
2134 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#lx.\n", hr);
2135 IMFPresentationDescriptor_Release(pd);
2136 IMFTopologyNode_Release(node);
2137 return MF_E_TOPO_MISSING_STREAM_DESCRIPTOR;
2140 hr = session_check_stream_descriptor(pd, sd);
2141 IMFPresentationDescriptor_Release(pd);
2142 IMFStreamDescriptor_Release(sd);
2143 if (FAILED(hr))
2145 IMFTopologyNode_Release(node);
2146 return hr;
2149 break;
2152 default:
2153 break;
2156 IMFTopologyNode_Release(node);
2159 return hr;
2162 static HRESULT WINAPI mfsession_SetTopology(IMFMediaSession *iface, DWORD flags, IMFTopology *topology)
2164 struct media_session *session = impl_from_IMFMediaSession(iface);
2165 struct session_op *op;
2166 HRESULT hr;
2168 TRACE("%p, %#lx, %p.\n", iface, flags, topology);
2170 if (FAILED(hr = session_check_topology(topology)))
2171 return hr;
2173 if (FAILED(hr = create_session_op(SESSION_CMD_SET_TOPOLOGY, &op)))
2174 return hr;
2176 op->set_topology.flags = flags;
2177 op->set_topology.topology = topology;
2178 if (op->set_topology.topology)
2179 IMFTopology_AddRef(op->set_topology.topology);
2181 hr = session_submit_command(session, op);
2182 IUnknown_Release(&op->IUnknown_iface);
2184 return hr;
2187 static HRESULT WINAPI mfsession_ClearTopologies(IMFMediaSession *iface)
2189 struct media_session *session = impl_from_IMFMediaSession(iface);
2191 TRACE("%p.\n", iface);
2193 return session_submit_simple_command(session, SESSION_CMD_CLEAR_TOPOLOGIES);
2196 static HRESULT WINAPI mfsession_Start(IMFMediaSession *iface, const GUID *format, const PROPVARIANT *start_position)
2198 struct media_session *session = impl_from_IMFMediaSession(iface);
2199 struct session_op *op;
2200 HRESULT hr;
2202 TRACE("%p, %s, %s.\n", iface, debugstr_guid(format), debugstr_propvar(start_position));
2204 if (!start_position)
2205 return E_POINTER;
2207 if (FAILED(hr = create_session_op(SESSION_CMD_START, &op)))
2208 return hr;
2210 op->start.time_format = format ? *format : GUID_NULL;
2211 hr = PropVariantCopy(&op->start.start_position, start_position);
2213 if (SUCCEEDED(hr))
2214 hr = session_submit_command(session, op);
2216 IUnknown_Release(&op->IUnknown_iface);
2217 return hr;
2220 static HRESULT WINAPI mfsession_Pause(IMFMediaSession *iface)
2222 struct media_session *session = impl_from_IMFMediaSession(iface);
2224 TRACE("%p.\n", iface);
2226 return session_submit_simple_command(session, SESSION_CMD_PAUSE);
2229 static HRESULT WINAPI mfsession_Stop(IMFMediaSession *iface)
2231 struct media_session *session = impl_from_IMFMediaSession(iface);
2233 TRACE("%p.\n", iface);
2235 return session_submit_simple_command(session, SESSION_CMD_STOP);
2238 static HRESULT WINAPI mfsession_Close(IMFMediaSession *iface)
2240 struct media_session *session = impl_from_IMFMediaSession(iface);
2242 TRACE("%p.\n", iface);
2244 return session_submit_simple_command(session, SESSION_CMD_CLOSE);
2247 static HRESULT WINAPI mfsession_Shutdown(IMFMediaSession *iface)
2249 struct media_session *session = impl_from_IMFMediaSession(iface);
2250 HRESULT hr = S_OK;
2252 TRACE("%p.\n", iface);
2254 EnterCriticalSection(&session->cs);
2255 if (SUCCEEDED(hr = session_is_shut_down(session)))
2257 session->state = SESSION_STATE_SHUT_DOWN;
2258 IMFMediaEventQueue_Shutdown(session->event_queue);
2259 if (session->quality_manager)
2260 IMFQualityManager_Shutdown(session->quality_manager);
2261 MFShutdownObject((IUnknown *)session->clock);
2262 IMFPresentationClock_Release(session->clock);
2263 session->clock = NULL;
2264 session_clear_presentation(session);
2265 session_clear_queued_topologies(session);
2266 session_submit_simple_command(session, SESSION_CMD_SHUTDOWN);
2268 LeaveCriticalSection(&session->cs);
2270 return hr;
2273 static HRESULT WINAPI mfsession_GetClock(IMFMediaSession *iface, IMFClock **clock)
2275 struct media_session *session = impl_from_IMFMediaSession(iface);
2276 HRESULT hr;
2278 TRACE("%p, %p.\n", iface, clock);
2280 EnterCriticalSection(&session->cs);
2281 if (SUCCEEDED(hr = session_is_shut_down(session)))
2283 *clock = (IMFClock *)session->clock;
2284 IMFClock_AddRef(*clock);
2286 LeaveCriticalSection(&session->cs);
2288 return hr;
2291 static HRESULT WINAPI mfsession_GetSessionCapabilities(IMFMediaSession *iface, DWORD *caps)
2293 struct media_session *session = impl_from_IMFMediaSession(iface);
2294 HRESULT hr = S_OK;
2296 TRACE("%p, %p.\n", iface, caps);
2298 if (!caps)
2299 return E_POINTER;
2301 EnterCriticalSection(&session->cs);
2302 if (SUCCEEDED(hr = session_is_shut_down(session)))
2303 *caps = session->caps;
2304 LeaveCriticalSection(&session->cs);
2306 return hr;
2309 static HRESULT WINAPI mfsession_GetFullTopology(IMFMediaSession *iface, DWORD flags, TOPOID id, IMFTopology **topology)
2311 struct media_session *session = impl_from_IMFMediaSession(iface);
2312 struct queued_topology *queued;
2313 TOPOID topo_id;
2314 HRESULT hr;
2316 TRACE("%p, %#lx, %s, %p.\n", iface, flags, wine_dbgstr_longlong(id), topology);
2318 *topology = NULL;
2320 EnterCriticalSection(&session->cs);
2322 if (SUCCEEDED(hr = session_is_shut_down(session)))
2324 if (flags & MFSESSION_GETFULLTOPOLOGY_CURRENT)
2326 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
2327 *topology = session->presentation.current_topology;
2328 else
2329 hr = MF_E_INVALIDREQUEST;
2331 else
2333 LIST_FOR_EACH_ENTRY(queued, &session->topologies, struct queued_topology, entry)
2335 if (SUCCEEDED(IMFTopology_GetTopologyID(queued->topology, &topo_id)) && topo_id == id)
2337 *topology = queued->topology;
2338 break;
2343 if (*topology)
2344 IMFTopology_AddRef(*topology);
2347 LeaveCriticalSection(&session->cs);
2349 return hr;
2352 static const IMFMediaSessionVtbl mfmediasessionvtbl =
2354 mfsession_QueryInterface,
2355 mfsession_AddRef,
2356 mfsession_Release,
2357 mfsession_GetEvent,
2358 mfsession_BeginGetEvent,
2359 mfsession_EndGetEvent,
2360 mfsession_QueueEvent,
2361 mfsession_SetTopology,
2362 mfsession_ClearTopologies,
2363 mfsession_Start,
2364 mfsession_Pause,
2365 mfsession_Stop,
2366 mfsession_Close,
2367 mfsession_Shutdown,
2368 mfsession_GetClock,
2369 mfsession_GetSessionCapabilities,
2370 mfsession_GetFullTopology,
2373 static HRESULT WINAPI session_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
2375 struct media_session *session = impl_from_IMFGetService(iface);
2376 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
2379 static ULONG WINAPI session_get_service_AddRef(IMFGetService *iface)
2381 struct media_session *session = impl_from_IMFGetService(iface);
2382 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2385 static ULONG WINAPI session_get_service_Release(IMFGetService *iface)
2387 struct media_session *session = impl_from_IMFGetService(iface);
2388 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2391 typedef BOOL (*p_renderer_node_test_func)(IMFMediaSink *sink);
2393 static BOOL session_video_renderer_test_func(IMFMediaSink *sink)
2395 IUnknown *obj;
2396 HRESULT hr;
2398 /* Use first sink to support IMFVideoRenderer. */
2399 hr = IMFMediaSink_QueryInterface(sink, &IID_IMFVideoRenderer, (void **)&obj);
2400 if (obj)
2401 IUnknown_Release(obj);
2403 return hr == S_OK;
2406 static BOOL session_audio_renderer_test_func(IMFMediaSink *sink)
2408 return mf_is_sar_sink(sink);
2411 static HRESULT session_get_renderer_node_service(struct media_session *session,
2412 p_renderer_node_test_func node_test_func, REFGUID service, REFIID riid, void **obj)
2414 HRESULT hr = E_NOINTERFACE;
2415 IMFStreamSink *stream_sink;
2416 IMFTopologyNode *node;
2417 IMFCollection *nodes;
2418 IMFMediaSink *sink;
2419 unsigned int i = 0;
2421 if (session->presentation.current_topology)
2423 if (SUCCEEDED(IMFTopology_GetOutputNodeCollection(session->presentation.current_topology,
2424 &nodes)))
2426 while (IMFCollection_GetElement(nodes, i++, (IUnknown **)&node) == S_OK)
2428 if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink)))
2430 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink)))
2432 if (node_test_func(sink))
2434 if (FAILED(hr = MFGetService((IUnknown *)sink, service, riid, obj)))
2435 WARN("Failed to get service from renderer node, %#lx.\n", hr);
2437 IMFMediaSink_Release(sink);
2439 IMFStreamSink_Release(stream_sink);
2442 IMFTopologyNode_Release(node);
2444 if (*obj)
2445 break;
2448 IMFCollection_Release(nodes);
2452 return hr;
2455 static HRESULT session_get_audio_render_service(struct media_session *session, REFGUID service,
2456 REFIID riid, void **obj)
2458 return session_get_renderer_node_service(session, session_audio_renderer_test_func,
2459 service, riid, obj);
2462 static HRESULT session_get_video_render_service(struct media_session *session, REFGUID service,
2463 REFIID riid, void **obj)
2465 return session_get_renderer_node_service(session, session_video_renderer_test_func,
2466 service, riid, obj);
2469 static HRESULT WINAPI session_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
2471 struct media_session *session = impl_from_IMFGetService(iface);
2472 HRESULT hr = S_OK;
2474 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
2476 *obj = NULL;
2478 EnterCriticalSection(&session->cs);
2479 if (FAILED(hr = session_is_shut_down(session)))
2482 else if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE))
2484 if (IsEqualIID(riid, &IID_IMFRateSupport))
2486 *obj = &session->IMFRateSupport_iface;
2488 else if (IsEqualIID(riid, &IID_IMFRateControl))
2490 *obj = &session->IMFRateControl_iface;
2492 else
2493 hr = E_NOINTERFACE;
2495 if (*obj)
2496 IUnknown_AddRef((IUnknown *)*obj);
2498 else if (IsEqualGUID(service, &MF_LOCAL_MFT_REGISTRATION_SERVICE))
2500 hr = IMFLocalMFTRegistration_QueryInterface(&local_mft_registration, riid, obj);
2502 else if (IsEqualGUID(service, &MF_TOPONODE_ATTRIBUTE_EDITOR_SERVICE))
2504 *obj = &session->IMFTopologyNodeAttributeEditor_iface;
2505 IUnknown_AddRef((IUnknown *)*obj);
2507 else if (IsEqualGUID(service, &MR_VIDEO_RENDER_SERVICE))
2509 hr = session_get_video_render_service(session, service, riid, obj);
2511 else if (IsEqualGUID(service, &MR_POLICY_VOLUME_SERVICE) ||
2512 IsEqualGUID(service, &MR_STREAM_VOLUME_SERVICE))
2514 hr = session_get_audio_render_service(session, service, riid, obj);
2516 else
2517 FIXME("Unsupported service %s.\n", debugstr_guid(service));
2519 LeaveCriticalSection(&session->cs);
2521 return hr;
2524 static const IMFGetServiceVtbl session_get_service_vtbl =
2526 session_get_service_QueryInterface,
2527 session_get_service_AddRef,
2528 session_get_service_Release,
2529 session_get_service_GetService,
2532 static HRESULT WINAPI session_commands_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
2534 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
2535 IsEqualIID(riid, &IID_IUnknown))
2537 *obj = iface;
2538 IMFAsyncCallback_AddRef(iface);
2539 return S_OK;
2542 WARN("Unsupported %s.\n", debugstr_guid(riid));
2543 *obj = NULL;
2544 return E_NOINTERFACE;
2547 static ULONG WINAPI session_commands_callback_AddRef(IMFAsyncCallback *iface)
2549 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2550 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2553 static ULONG WINAPI session_commands_callback_Release(IMFAsyncCallback *iface)
2555 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2556 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2559 static HRESULT WINAPI session_commands_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
2561 return E_NOTIMPL;
2564 static void session_deliver_pending_samples(struct media_session *session, IMFTopologyNode *node);
2566 static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
2568 struct session_op *op = impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result));
2569 struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
2571 TRACE("session %p, op %p, command %u.\n", session, op, op->command);
2573 EnterCriticalSection(&session->cs);
2575 if (session->presentation.flags & SESSION_FLAG_PENDING_COMMAND)
2577 WARN("session %p command is in progress, waiting for it to complete.\n", session);
2578 LeaveCriticalSection(&session->cs);
2579 return S_OK;
2582 list_remove(&op->entry);
2583 session->presentation.flags |= SESSION_FLAG_PENDING_COMMAND;
2585 switch (op->command)
2587 case SESSION_CMD_CLEAR_TOPOLOGIES:
2588 session_clear_topologies(session);
2589 break;
2590 case SESSION_CMD_SET_TOPOLOGY:
2591 session_set_topology(session, op->set_topology.flags, op->set_topology.topology);
2592 session_command_complete(session);
2593 break;
2594 case SESSION_CMD_START:
2595 session_start(session, &op->start.time_format, &op->start.start_position);
2596 break;
2597 case SESSION_CMD_PAUSE:
2598 session_pause(session);
2599 break;
2600 case SESSION_CMD_STOP:
2601 session_stop(session);
2602 break;
2603 case SESSION_CMD_CLOSE:
2604 session_close(session);
2605 break;
2606 case SESSION_CMD_SET_RATE:
2607 session_set_rate(session, op->set_rate.thin, op->set_rate.rate);
2608 break;
2609 case SESSION_CMD_SHUTDOWN:
2610 session_clear_command_list(session);
2611 session_command_complete(session);
2612 break;
2613 default:
2617 LeaveCriticalSection(&session->cs);
2619 IUnknown_Release(&op->IUnknown_iface);
2621 return S_OK;
2624 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl =
2626 session_commands_callback_QueryInterface,
2627 session_commands_callback_AddRef,
2628 session_commands_callback_Release,
2629 session_commands_callback_GetParameters,
2630 session_commands_callback_Invoke,
2633 static HRESULT WINAPI session_sa_ready_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
2635 if (IsEqualIID(riid, &IID_IMFAsyncCallback)
2636 || IsEqualIID(riid, &IID_IUnknown))
2638 *obj = iface;
2639 IMFAsyncCallback_AddRef(iface);
2640 return S_OK;
2643 WARN("Unsupported %s.\n", debugstr_guid(riid));
2644 *obj = NULL;
2645 return E_NOINTERFACE;
2648 static ULONG WINAPI session_sa_ready_callback_AddRef(IMFAsyncCallback *iface)
2650 struct media_session *session = impl_from_sa_ready_callback_IMFAsyncCallback(iface);
2651 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2654 static ULONG WINAPI session_sa_ready_callback_Release(IMFAsyncCallback *iface)
2656 struct media_session *session = impl_from_sa_ready_callback_IMFAsyncCallback(iface);
2657 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2660 static HRESULT WINAPI session_sa_ready_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
2662 return E_NOTIMPL;
2665 static HRESULT WINAPI session_sa_ready_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
2667 IMFVideoSampleAllocatorNotify *notify = (IMFVideoSampleAllocatorNotify *)IMFAsyncResult_GetStateNoAddRef(result);
2668 struct topo_node *topo_node = impl_node_from_IMFVideoSampleAllocatorNotify(notify);
2669 struct media_session *session = impl_from_sa_ready_callback_IMFAsyncCallback(iface);
2670 IMFTopologyNode *upstream_node;
2671 DWORD upstream_output;
2673 EnterCriticalSection(&session->cs);
2675 if (topo_node->u.sink.requests)
2677 if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node->node, 0, &upstream_node, &upstream_output)))
2679 session_deliver_pending_samples(session, upstream_node);
2680 IMFTopologyNode_Release(upstream_node);
2684 LeaveCriticalSection(&session->cs);
2686 return S_OK;
2689 static const IMFAsyncCallbackVtbl session_sa_ready_callback_vtbl =
2691 session_sa_ready_callback_QueryInterface,
2692 session_sa_ready_callback_AddRef,
2693 session_sa_ready_callback_Release,
2694 session_sa_ready_callback_GetParameters,
2695 session_sa_ready_callback_Invoke,
2698 static HRESULT WINAPI session_events_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
2700 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
2701 IsEqualIID(riid, &IID_IUnknown))
2703 *obj = iface;
2704 IMFAsyncCallback_AddRef(iface);
2705 return S_OK;
2708 WARN("Unsupported %s.\n", debugstr_guid(riid));
2709 *obj = NULL;
2710 return E_NOINTERFACE;
2713 static ULONG WINAPI session_events_callback_AddRef(IMFAsyncCallback *iface)
2715 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
2716 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
2719 static ULONG WINAPI session_events_callback_Release(IMFAsyncCallback *iface)
2721 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
2722 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
2725 static HRESULT WINAPI session_events_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
2727 return E_NOTIMPL;
2730 static HRESULT session_add_media_stream(struct media_session *session, IMFMediaSource *source, IMFMediaStream *stream)
2732 struct topo_node *node;
2733 IMFStreamDescriptor *sd;
2734 DWORD stream_id = 0;
2735 HRESULT hr;
2737 if (FAILED(hr = IMFMediaStream_GetStreamDescriptor(stream, &sd)))
2738 return hr;
2740 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &stream_id);
2741 IMFStreamDescriptor_Release(sd);
2742 if (FAILED(hr))
2743 return hr;
2745 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2747 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->u.source.source == source
2748 && node->u.source.stream_id == stream_id)
2750 if (node->object.source_stream)
2752 WARN("Node already has stream set.\n");
2753 return S_FALSE;
2756 node->object.source_stream = stream;
2757 IMFMediaStream_AddRef(node->object.source_stream);
2758 break;
2762 return S_OK;
2765 static BOOL session_is_source_nodes_state(struct media_session *session, enum object_state state)
2767 struct media_source *source;
2768 struct topo_node *node;
2770 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
2772 if (source->state != state)
2773 return FALSE;
2776 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2778 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->state != state)
2779 return FALSE;
2782 return TRUE;
2785 static BOOL session_is_output_nodes_state(struct media_session *session, enum object_state state)
2787 struct topo_node *node;
2789 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2791 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->state != state)
2792 return FALSE;
2795 return TRUE;
2798 static enum object_state session_get_object_state_for_event(MediaEventType event)
2800 switch (event)
2802 case MESourceSeeked:
2803 case MEStreamSeeked:
2804 case MESourceStarted:
2805 case MEStreamStarted:
2806 case MEStreamSinkStarted:
2807 return OBJ_STATE_STARTED;
2808 case MESourcePaused:
2809 case MEStreamPaused:
2810 case MEStreamSinkPaused:
2811 return OBJ_STATE_PAUSED;
2812 case MESourceStopped:
2813 case MEStreamStopped:
2814 case MEStreamSinkStopped:
2815 return OBJ_STATE_STOPPED;
2816 case MEStreamSinkPrerolled:
2817 return OBJ_STATE_PREROLLED;
2818 default:
2819 return OBJ_STATE_INVALID;
2823 static HRESULT session_start_clock(struct media_session *session)
2825 LONGLONG start_offset = 0;
2826 HRESULT hr;
2828 if (IsEqualGUID(&session->presentation.time_format, &GUID_NULL))
2830 if (session->presentation.start_position.vt == VT_EMPTY)
2831 start_offset = PRESENTATION_CURRENT_POSITION;
2832 else if (session->presentation.start_position.vt == VT_I8)
2833 start_offset = session->presentation.start_position.hVal.QuadPart;
2834 else
2835 FIXME("Unhandled position type %d.\n", session->presentation.start_position.vt);
2837 else
2838 FIXME("Unhandled time format %s.\n", debugstr_guid(&session->presentation.time_format));
2840 if (FAILED(hr = IMFPresentationClock_Start(session->clock, start_offset)))
2841 WARN("Failed to start session clock, hr %#lx.\n", hr);
2843 return hr;
2846 static struct topo_node *session_get_node_object(struct media_session *session, IUnknown *object,
2847 MF_TOPOLOGY_TYPE node_type)
2849 struct topo_node *node = NULL;
2851 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2853 if (node->type == node_type && object == node->object.object)
2854 break;
2857 return node;
2860 static BOOL session_set_node_object_state(struct media_session *session, IUnknown *object,
2861 MF_TOPOLOGY_TYPE node_type, enum object_state state)
2863 struct topo_node *node;
2864 BOOL changed = FALSE;
2866 if ((node = session_get_node_object(session, object, node_type)))
2868 changed = node->state != state;
2869 node->state = state;
2872 return changed;
2875 static void session_set_source_object_state(struct media_session *session, IUnknown *object,
2876 MediaEventType event_type)
2878 IMFStreamSink *stream_sink;
2879 struct media_source *src;
2880 struct media_sink *sink;
2881 enum object_state state;
2882 struct topo_node *node;
2883 BOOL changed = FALSE;
2884 DWORD i, count;
2885 HRESULT hr;
2887 if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
2888 return;
2890 switch (event_type)
2892 case MESourceSeeked:
2893 case MESourceStarted:
2894 case MESourcePaused:
2895 case MESourceStopped:
2897 LIST_FOR_EACH_ENTRY(src, &session->presentation.sources, struct media_source, entry)
2899 if (object == src->object)
2901 changed = src->state != state;
2902 src->state = state;
2903 break;
2906 break;
2907 case MEStreamSeeked:
2908 case MEStreamStarted:
2909 case MEStreamPaused:
2910 case MEStreamStopped:
2912 changed = session_set_node_object_state(session, object, MF_TOPOLOGY_SOURCESTREAM_NODE, state);
2913 default:
2917 if (!changed)
2918 return;
2920 switch (session->state)
2922 case SESSION_STATE_STARTING_SOURCES:
2923 if (!session_is_source_nodes_state(session, OBJ_STATE_STARTED))
2924 break;
2926 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_STARTED_SOURCE);
2928 session_set_presentation_clock(session);
2930 if (session->presentation.flags & SESSION_FLAG_NEEDS_PREROLL)
2932 MFTIME preroll_time = 0;
2934 if (session->presentation.start_position.vt == VT_I8)
2935 preroll_time = session->presentation.start_position.hVal.QuadPart;
2937 /* Mark stream sinks without prerolling support as PREROLLED to keep state test logic generic. */
2938 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
2940 if (sink->preroll)
2942 /* FIXME: abort and enter error state on failure. */
2943 if (FAILED(hr = IMFMediaSinkPreroll_NotifyPreroll(sink->preroll, preroll_time)))
2944 WARN("Preroll notification failed, hr %#lx.\n", hr);
2946 else
2948 if (SUCCEEDED(IMFMediaSink_GetStreamSinkCount(sink->sink, &count)))
2950 for (i = 0; i < count; ++i)
2952 if (SUCCEEDED(IMFMediaSink_GetStreamSinkByIndex(sink->sink, i, &stream_sink)))
2954 session_set_node_object_state(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE,
2955 OBJ_STATE_PREROLLED);
2956 IMFStreamSink_Release(stream_sink);
2962 session->state = SESSION_STATE_PREROLLING_SINKS;
2964 else if (SUCCEEDED(session_start_clock(session)))
2965 session->state = SESSION_STATE_STARTING_SINKS;
2967 break;
2968 case SESSION_STATE_PAUSING_SOURCES:
2969 if (!session_is_source_nodes_state(session, OBJ_STATE_PAUSED))
2970 break;
2972 session_set_paused(session, SESSION_STATE_PAUSED, S_OK);
2973 break;
2974 case SESSION_STATE_STOPPING_SOURCES:
2975 if (!session_is_source_nodes_state(session, OBJ_STATE_STOPPED))
2976 break;
2978 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
2980 switch (node->type)
2982 case MF_TOPOLOGY_OUTPUT_NODE:
2983 IMFStreamSink_Flush(node->object.sink_stream);
2984 break;
2985 case MF_TOPOLOGY_TRANSFORM_NODE:
2986 IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_COMMAND_FLUSH, 0);
2987 break;
2988 default:
2993 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
2995 if (session->presentation.flags & SESSION_FLAG_FINALIZE_SINKS)
2996 session_finalize_sinks(session);
2997 else
2998 session_set_stopped(session, S_OK);
3000 break;
3001 default:
3006 static void session_set_sink_stream_state(struct media_session *session, IMFStreamSink *stream,
3007 MediaEventType event_type)
3009 struct media_source *source;
3010 enum object_state state;
3011 HRESULT hr = S_OK;
3012 BOOL changed;
3014 if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
3015 return;
3017 if (!(changed = session_set_node_object_state(session, (IUnknown *)stream, MF_TOPOLOGY_OUTPUT_NODE, state)))
3018 return;
3020 switch (session->state)
3022 case SESSION_STATE_PREROLLING_SINKS:
3023 if (!session_is_output_nodes_state(session, OBJ_STATE_PREROLLED))
3024 break;
3026 if (SUCCEEDED(session_start_clock(session)))
3027 session->state = SESSION_STATE_STARTING_SINKS;
3028 break;
3029 case SESSION_STATE_STARTING_SINKS:
3030 if (!session_is_output_nodes_state(session, OBJ_STATE_STARTED))
3031 break;
3033 session_set_started(session);
3034 break;
3035 case SESSION_STATE_PAUSING_SINKS:
3036 if (!session_is_output_nodes_state(session, OBJ_STATE_PAUSED))
3037 break;
3039 session->state = SESSION_STATE_PAUSING_SOURCES;
3041 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3043 if (FAILED(hr = IMFMediaSource_Pause(source->source)))
3044 break;
3047 if (FAILED(hr))
3048 session_set_paused(session, SESSION_STATE_PAUSED, hr);
3050 break;
3051 case SESSION_STATE_STOPPING_SINKS:
3052 if (!session_is_output_nodes_state(session, OBJ_STATE_STOPPED))
3053 break;
3055 session->state = SESSION_STATE_STOPPING_SOURCES;
3057 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3059 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION)
3060 IMFMediaSource_Stop(source->source);
3061 else if (FAILED(hr = IMFMediaSource_Stop(source->source)))
3062 break;
3065 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION || FAILED(hr))
3066 session_set_stopped(session, hr);
3068 break;
3069 default:
3074 static HRESULT transform_get_external_output_sample(const struct media_session *session, struct topo_node *transform,
3075 unsigned int output_index, const MFT_OUTPUT_STREAM_INFO *stream_info, IMFSample **sample)
3077 IMFTopologyNode *downstream_node;
3078 IMFMediaBuffer *buffer = NULL;
3079 struct topo_node *topo_node;
3080 unsigned int buffer_size;
3081 DWORD downstream_input;
3082 TOPOID node_id;
3083 HRESULT hr;
3085 if (FAILED(IMFTopologyNode_GetOutput(transform->node, output_index, &downstream_node, &downstream_input)))
3087 WARN("Failed to get connected node for output %u.\n", output_index);
3088 return MF_E_UNEXPECTED;
3091 IMFTopologyNode_GetTopoNodeID(downstream_node, &node_id);
3092 IMFTopologyNode_Release(downstream_node);
3094 topo_node = session_get_node_by_id(session, node_id);
3096 if (topo_node->type == MF_TOPOLOGY_OUTPUT_NODE && topo_node->u.sink.allocator)
3098 hr = IMFVideoSampleAllocator_AllocateSample(topo_node->u.sink.allocator, sample);
3100 else
3102 buffer_size = max(stream_info->cbSize, transform->u.transform.outputs[output_index].min_buffer_size);
3104 hr = MFCreateAlignedMemoryBuffer(buffer_size, stream_info->cbAlignment, &buffer);
3105 if (SUCCEEDED(hr))
3106 hr = MFCreateSample(sample);
3108 if (SUCCEEDED(hr))
3109 hr = IMFSample_AddBuffer(*sample, buffer);
3111 if (buffer)
3112 IMFMediaBuffer_Release(buffer);
3115 return hr;
3118 static HRESULT transform_node_pull_samples(const struct media_session *session, struct topo_node *node)
3120 MFT_OUTPUT_STREAM_INFO stream_info;
3121 MFT_OUTPUT_DATA_BUFFER *buffers;
3122 HRESULT hr = E_UNEXPECTED;
3123 DWORD status = 0;
3124 unsigned int i;
3126 if (!(buffers = calloc(node->u.transform.output_count, sizeof(*buffers))))
3127 return E_OUTOFMEMORY;
3129 for (i = 0; i < node->u.transform.output_count; ++i)
3131 buffers[i].dwStreamID = transform_node_get_stream_id(node, TRUE, i);
3132 buffers[i].pSample = NULL;
3133 buffers[i].dwStatus = 0;
3134 buffers[i].pEvents = NULL;
3136 memset(&stream_info, 0, sizeof(stream_info));
3137 if (FAILED(hr = IMFTransform_GetOutputStreamInfo(node->object.transform, buffers[i].dwStreamID, &stream_info)))
3138 break;
3140 if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)))
3142 if (FAILED(hr = transform_get_external_output_sample(session, node, i, &stream_info, &buffers[i].pSample)))
3143 break;
3147 if (SUCCEEDED(hr))
3148 hr = IMFTransform_ProcessOutput(node->object.transform, 0, node->u.transform.output_count, buffers, &status);
3150 /* Collect returned samples for all streams. */
3151 for (i = 0; i < node->u.transform.output_count; ++i)
3153 struct transform_stream *stream = &node->u.transform.outputs[i];
3155 if (buffers[i].pEvents)
3156 IMFCollection_Release(buffers[i].pEvents);
3158 if (SUCCEEDED(hr) && !(buffers[i].dwStatus & MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE))
3160 if (session->quality_manager)
3161 IMFQualityManager_NotifyProcessOutput(session->quality_manager, node->node, i, buffers[i].pSample);
3162 if (FAILED(hr = transform_stream_push_sample(stream, buffers[i].pSample)))
3163 WARN("Failed to queue output sample, hr %#lx\n", hr);
3166 if (buffers[i].pSample)
3167 IMFSample_Release(buffers[i].pSample);
3170 free(buffers);
3172 return hr;
3175 static BOOL transform_node_is_drained(struct topo_node *topo_node)
3177 UINT i;
3179 for (i = 0; i < topo_node->u.transform.input_count; i++)
3181 struct transform_stream *stream = &topo_node->u.transform.inputs[i];
3182 if (!stream->draining)
3183 return FALSE;
3186 return TRUE;
3189 static BOOL transform_node_has_requests(struct topo_node *topo_node)
3191 UINT i;
3193 for (i = 0; i < topo_node->u.transform.output_count; i++)
3194 if (topo_node->u.transform.outputs[i].requests)
3195 return TRUE;
3197 return FALSE;
3200 static HRESULT transform_node_push_sample(const struct media_session *session, struct topo_node *topo_node,
3201 UINT input, IMFSample *sample)
3203 struct transform_stream *stream = &topo_node->u.transform.inputs[input];
3204 UINT id = transform_node_get_stream_id(topo_node, FALSE, input);
3205 IMFTransform *transform = topo_node->object.transform;
3206 HRESULT hr;
3208 if (sample)
3210 hr = IMFTransform_ProcessInput(transform, id, sample, 0);
3211 if (hr == MF_E_NOTACCEPTING)
3212 hr = transform_stream_push_sample(stream, sample);
3214 else
3216 if (FAILED(hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, id)))
3217 WARN("Drain command failed for transform, hr %#lx.\n", hr);
3218 else
3219 stream->draining = TRUE;
3222 return hr;
3225 static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input,
3226 IMFSample *sample);
3228 static void transform_node_deliver_samples(struct media_session *session, struct topo_node *topo_node)
3230 IMFTopologyNode *up_node = topo_node->node, *down_node;
3231 BOOL drained = transform_node_is_drained(topo_node);
3232 DWORD output, input;
3233 IMFSample *sample;
3234 HRESULT hr = S_OK;
3236 /* Push down all available output. */
3237 for (output = 0; SUCCEEDED(hr) && output < topo_node->u.transform.output_count; ++output)
3239 struct transform_stream *stream = &topo_node->u.transform.outputs[output];
3241 if (FAILED(hr = IMFTopologyNode_GetOutput(up_node, output, &down_node, &input)))
3243 WARN("Failed to node %p/%lu output, hr %#lx.\n", up_node, output, hr);
3244 continue;
3247 while (stream->requests)
3249 if (FAILED(hr = transform_stream_pop_sample(stream, &sample)))
3251 /* try getting more samples by calling IMFTransform_ProcessOutput */
3252 if (FAILED(hr = transform_node_pull_samples(session, topo_node)))
3253 break;
3254 if (FAILED(hr = transform_stream_pop_sample(stream, &sample)))
3255 break;
3258 session_deliver_sample_to_node(session, down_node, input, sample);
3259 stream->requests--;
3260 IMFSample_Release(sample);
3263 while (stream->requests && drained)
3265 session_deliver_sample_to_node(session, down_node, input, NULL);
3266 stream->requests--;
3269 IMFTopologyNode_Release(down_node);
3272 if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT && transform_node_has_requests(topo_node))
3274 struct transform_stream *stream;
3276 input = topo_node->u.transform.next_input++ % topo_node->u.transform.input_count;
3277 stream = &topo_node->u.transform.inputs[input];
3279 if (SUCCEEDED(transform_stream_pop_sample(stream, &sample)))
3280 session_deliver_sample_to_node(session, topo_node->node, input, sample);
3281 else if (FAILED(hr = IMFTopologyNode_GetInput(topo_node->node, input, &up_node, &output)))
3282 WARN("Failed to get node %p/%lu input, hr %#lx\n", topo_node->node, input, hr);
3283 else
3285 if (FAILED(hr = session_request_sample_from_node(session, up_node, output)))
3286 WARN("Failed to request sample from upstream node %p/%lu, hr %#lx\n", up_node, output, hr);
3287 IMFTopologyNode_Release(up_node);
3292 static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input,
3293 IMFSample *sample)
3295 struct topo_node *topo_node;
3296 MF_TOPOLOGY_TYPE node_type;
3297 TOPOID node_id;
3298 HRESULT hr;
3300 if (session->quality_manager)
3301 IMFQualityManager_NotifyProcessInput(session->quality_manager, node, input, sample);
3303 IMFTopologyNode_GetNodeType(node, &node_type);
3304 IMFTopologyNode_GetTopoNodeID(node, &node_id);
3306 topo_node = session_get_node_by_id(session, node_id);
3308 switch (node_type)
3310 case MF_TOPOLOGY_OUTPUT_NODE:
3311 if (topo_node->u.sink.requests)
3313 if (sample)
3315 if (FAILED(hr = IMFStreamSink_ProcessSample(topo_node->object.sink_stream, sample)))
3316 WARN("Stream sink failed to process sample, hr %#lx.\n", hr);
3318 else if (FAILED(hr = IMFStreamSink_PlaceMarker(topo_node->object.sink_stream, MFSTREAMSINK_MARKER_ENDOFSEGMENT,
3319 NULL, NULL)))
3321 WARN("Failed to place sink marker, hr %#lx.\n", hr);
3323 topo_node->u.sink.requests--;
3325 break;
3326 case MF_TOPOLOGY_TRANSFORM_NODE:
3327 if (FAILED(hr = transform_node_push_sample(session, topo_node, input, sample)))
3328 WARN("Failed to push or queue sample to transform, hr %#lx\n", hr);
3329 transform_node_pull_samples(session, topo_node);
3330 transform_node_deliver_samples(session, topo_node);
3331 break;
3332 case MF_TOPOLOGY_TEE_NODE:
3333 FIXME("Unhandled downstream node type %d.\n", node_type);
3334 break;
3335 default:
3340 static void session_deliver_pending_samples(struct media_session *session, IMFTopologyNode *node)
3342 struct topo_node *topo_node;
3343 MF_TOPOLOGY_TYPE node_type;
3344 TOPOID node_id;
3346 IMFTopologyNode_GetNodeType(node, &node_type);
3347 IMFTopologyNode_GetTopoNodeID(node, &node_id);
3349 topo_node = session_get_node_by_id(session, node_id);
3351 switch (node_type)
3353 case MF_TOPOLOGY_TRANSFORM_NODE:
3354 transform_node_pull_samples(session, topo_node);
3355 transform_node_deliver_samples(session, topo_node);
3356 break;
3357 default:
3358 FIXME("Unexpected node type %u.\n", node_type);
3363 static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output)
3365 IMFTopologyNode *down_node;
3366 struct topo_node *topo_node;
3367 MF_TOPOLOGY_TYPE node_type;
3368 HRESULT hr = S_OK;
3369 IMFSample *sample;
3370 TOPOID node_id;
3371 DWORD input;
3373 IMFTopologyNode_GetNodeType(node, &node_type);
3374 IMFTopologyNode_GetTopoNodeID(node, &node_id);
3376 topo_node = session_get_node_by_id(session, node_id);
3378 switch (node_type)
3380 case MF_TOPOLOGY_SOURCESTREAM_NODE:
3381 if (FAILED(hr = IMFMediaStream_RequestSample(topo_node->object.source_stream, NULL)))
3382 WARN("Sample request failed, hr %#lx.\n", hr);
3383 break;
3384 case MF_TOPOLOGY_TRANSFORM_NODE:
3386 struct transform_stream *stream = &topo_node->u.transform.outputs[output];
3388 if (FAILED(hr = IMFTopologyNode_GetOutput(node, output, &down_node, &input)))
3390 WARN("Failed to node %p/%lu output, hr %#lx.\n", node, output, hr);
3391 break;
3394 if (SUCCEEDED(transform_stream_pop_sample(stream, &sample)))
3396 session_deliver_sample_to_node(session, down_node, input, sample);
3397 IMFSample_Release(sample);
3399 else if (transform_node_has_requests(topo_node))
3401 /* there's already requests pending, just increase the counter */
3402 stream->requests++;
3404 else
3406 stream->requests++;
3407 transform_node_deliver_samples(session, topo_node);
3410 IMFTopologyNode_Release(down_node);
3411 break;
3413 case MF_TOPOLOGY_TEE_NODE:
3414 FIXME("Unhandled upstream node type %d.\n", node_type);
3415 default:
3416 hr = E_UNEXPECTED;
3419 return hr;
3422 static void session_request_sample(struct media_session *session, IMFStreamSink *sink_stream)
3424 struct topo_node *sink_node = NULL, *node;
3425 IMFTopologyNode *upstream_node;
3426 DWORD upstream_output;
3427 HRESULT hr;
3429 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
3431 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink_stream)
3433 sink_node = node;
3434 break;
3438 if (!sink_node)
3439 return;
3441 if (FAILED(hr = IMFTopologyNode_GetInput(sink_node->node, 0, &upstream_node, &upstream_output)))
3443 WARN("Failed to get upstream node connection, hr %#lx.\n", hr);
3444 return;
3447 sink_node->u.sink.requests++;
3448 if (FAILED(session_request_sample_from_node(session, upstream_node, upstream_output)))
3449 sink_node->u.sink.requests--;
3450 IMFTopologyNode_Release(upstream_node);
3453 static void session_deliver_sample(struct media_session *session, IMFMediaStream *stream, const PROPVARIANT *value)
3455 struct topo_node *source_node = NULL, *node;
3456 IMFTopologyNode *downstream_node;
3457 DWORD downstream_input;
3458 HRESULT hr;
3460 if (value && (value->vt != VT_UNKNOWN || !value->punkVal))
3462 WARN("Unexpected value type %d.\n", value->vt);
3463 return;
3466 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
3468 if (node->type == MF_TOPOLOGY_SOURCESTREAM_NODE && node->object.source_stream == stream)
3470 source_node = node;
3471 break;
3475 if (!source_node)
3476 return;
3478 if (!value)
3479 source_node->flags |= TOPO_NODE_END_OF_STREAM;
3481 if (FAILED(hr = IMFTopologyNode_GetOutput(source_node->node, 0, &downstream_node, &downstream_input)))
3483 WARN("Failed to get downstream node connection, hr %#lx.\n", hr);
3484 return;
3487 session_deliver_sample_to_node(session, downstream_node, downstream_input, value ? (IMFSample *)value->punkVal : NULL);
3488 IMFTopologyNode_Release(downstream_node);
3491 static void session_sink_invalidated(struct media_session *session, IMFMediaEvent *event, IMFStreamSink *sink)
3493 struct topo_node *node, *sink_node = NULL;
3494 HRESULT hr;
3496 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
3498 if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink)
3500 sink_node = node;
3501 break;
3505 if (!sink_node)
3506 return;
3508 if (!event)
3510 if (FAILED(hr = MFCreateMediaEvent(MESinkInvalidated, &GUID_NULL, S_OK, NULL, &event)))
3511 WARN("Failed to create event, hr %#lx.\n", hr);
3514 if (!event)
3515 return;
3517 IMFMediaEvent_SetUINT64(event, &MF_EVENT_OUTPUT_NODE, sink_node->node_id);
3518 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3520 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED);
3523 static BOOL session_nodes_is_mask_set(struct media_session *session, MF_TOPOLOGY_TYPE node_type, unsigned int flags)
3525 struct media_source *source;
3526 struct topo_node *node;
3528 if (node_type == MF_TOPOLOGY_MAX)
3530 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3532 if ((source->flags & flags) != flags)
3533 return FALSE;
3536 else
3538 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
3540 if (node->type == node_type && (node->flags & flags) != flags)
3541 return FALSE;
3545 return TRUE;
3548 static void session_nodes_unset_mask(struct media_session *session, MF_TOPOLOGY_TYPE node_type, unsigned int flags)
3550 struct media_source *source;
3551 struct topo_node *node;
3553 if (node_type == MF_TOPOLOGY_MAX)
3555 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3557 source->flags &= ~flags;
3560 else
3562 LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
3564 if (node->type == node_type)
3566 node->flags &= ~flags;
3572 static void session_raise_end_of_presentation(struct media_session *session)
3574 if (!(session_nodes_is_mask_set(session, MF_TOPOLOGY_SOURCESTREAM_NODE, TOPO_NODE_END_OF_STREAM)))
3575 return;
3577 if (!(session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION))
3579 if (session_nodes_is_mask_set(session, MF_TOPOLOGY_MAX, SOURCE_FLAG_END_OF_PRESENTATION))
3581 session->presentation.flags |= SESSION_FLAG_END_OF_PRESENTATION | SESSION_FLAG_PENDING_COMMAND;
3582 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, NULL);
3587 static void session_handle_end_of_stream(struct media_session *session, IMFMediaStream *stream)
3589 struct topo_node *node;
3591 if (!(node = session_get_node_object(session, (IUnknown *)stream, MF_TOPOLOGY_SOURCESTREAM_NODE))
3592 || node->flags & TOPO_NODE_END_OF_STREAM)
3594 return;
3597 session_deliver_sample(session, stream, NULL);
3599 session_raise_end_of_presentation(session);
3602 static void session_handle_end_of_presentation(struct media_session *session, IMFMediaSource *object)
3604 struct media_source *source;
3606 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
3608 if (source->source == object)
3610 if (!(source->flags & SOURCE_FLAG_END_OF_PRESENTATION))
3612 source->flags |= SOURCE_FLAG_END_OF_PRESENTATION;
3613 session_raise_end_of_presentation(session);
3616 break;
3621 static void session_sink_stream_marker(struct media_session *session, IMFStreamSink *stream_sink)
3623 struct topo_node *node;
3625 if (!(node = session_get_node_object(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE))
3626 || node->flags & TOPO_NODE_END_OF_STREAM)
3628 return;
3631 node->flags |= TOPO_NODE_END_OF_STREAM;
3633 if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION &&
3634 session_nodes_is_mask_set(session, MF_TOPOLOGY_OUTPUT_NODE, TOPO_NODE_END_OF_STREAM))
3636 session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED);
3637 session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
3638 session_stop(session);
3642 static void session_sink_stream_scrub_complete(struct media_session *session, IMFStreamSink *stream_sink)
3644 struct topo_node *node;
3646 if (!(node = session_get_node_object(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE))
3647 || node->flags & TOPO_NODE_SCRUB_SAMPLE_COMPLETE)
3649 return;
3652 node->flags |= TOPO_NODE_SCRUB_SAMPLE_COMPLETE;
3654 /* Scrubbing event is not limited to the started state transition, or even the started state.
3655 Events are processed and forwarded at any point after transition from initial idle state. */
3656 if (session->presentation.flags & SESSION_FLAG_SOURCES_SUBSCRIBED &&
3657 session_nodes_is_mask_set(session, MF_TOPOLOGY_OUTPUT_NODE, TOPO_NODE_SCRUB_SAMPLE_COMPLETE))
3659 IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionScrubSampleComplete, &GUID_NULL, S_OK, NULL);
3660 session_nodes_unset_mask(session, MF_TOPOLOGY_OUTPUT_NODE, TOPO_NODE_SCRUB_SAMPLE_COMPLETE);
3664 static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
3666 struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
3667 IMFMediaEventGenerator *event_source;
3668 IMFMediaEvent *event = NULL;
3669 MediaEventType event_type;
3670 IUnknown *object = NULL;
3671 IMFMediaSource *source;
3672 IMFMediaStream *stream;
3673 PROPVARIANT value;
3674 HRESULT hr;
3676 if (FAILED(hr = IMFAsyncResult_GetState(result, (IUnknown **)&event_source)))
3677 return hr;
3679 if (FAILED(hr = IMFMediaEventGenerator_EndGetEvent(event_source, result, &event)))
3681 WARN("Failed to get event from %p, hr %#lx.\n", event_source, hr);
3682 goto failed;
3685 if (FAILED(hr = IMFMediaEvent_GetType(event, &event_type)))
3687 WARN("Failed to get event type, hr %#lx.\n", hr);
3688 goto failed;
3691 value.vt = VT_EMPTY;
3692 if (FAILED(hr = IMFMediaEvent_GetValue(event, &value)))
3694 WARN("Failed to get event value, hr %#lx.\n", hr);
3695 goto failed;
3698 switch (event_type)
3700 case MESourceSeeked:
3701 case MEStreamSeeked:
3702 FIXME("Source/stream seeking, semi-stub!\n");
3703 /* fallthrough */
3704 case MESourceStarted:
3705 case MESourcePaused:
3706 case MESourceStopped:
3707 case MEStreamStarted:
3708 case MEStreamPaused:
3709 case MEStreamStopped:
3711 EnterCriticalSection(&session->cs);
3712 session_set_source_object_state(session, (IUnknown *)event_source, event_type);
3713 LeaveCriticalSection(&session->cs);
3715 break;
3717 case MESourceRateChanged:
3719 EnterCriticalSection(&session->cs);
3720 session_complete_rate_change(session);
3721 LeaveCriticalSection(&session->cs);
3723 break;
3725 case MEBufferingStarted:
3726 case MEBufferingStopped:
3728 EnterCriticalSection(&session->cs);
3729 if (session_get_media_source(session, (IMFMediaSource *)event_source))
3731 if (event_type == MEBufferingStarted)
3732 IMFPresentationClock_Pause(session->clock);
3733 else
3734 IMFPresentationClock_Start(session->clock, PRESENTATION_CURRENT_POSITION);
3736 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3738 LeaveCriticalSection(&session->cs);
3739 break;
3741 case MEReconnectStart:
3742 case MEReconnectEnd:
3744 EnterCriticalSection(&session->cs);
3745 if (session_get_media_source(session, (IMFMediaSource *)event_source))
3746 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3747 LeaveCriticalSection(&session->cs);
3748 break;
3750 case MEExtendedType:
3751 case MERendererEvent:
3752 case MEStreamSinkFormatChanged:
3754 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3755 break;
3757 case MENewStream:
3758 stream = (IMFMediaStream *)value.punkVal;
3760 if (value.vt != VT_UNKNOWN || !stream)
3762 WARN("Unexpected event value.\n");
3763 break;
3766 if (FAILED(hr = IMFMediaStream_GetMediaSource(stream, &source)))
3767 break;
3769 EnterCriticalSection(&session->cs);
3770 if (SUCCEEDED(hr = session_add_media_stream(session, source, stream)))
3771 hr = IMFMediaStream_BeginGetEvent(stream, &session->events_callback, (IUnknown *)stream);
3772 LeaveCriticalSection(&session->cs);
3774 IMFMediaSource_Release(source);
3776 break;
3777 case MEStreamSinkStarted:
3778 case MEStreamSinkPaused:
3779 case MEStreamSinkStopped:
3780 case MEStreamSinkPrerolled:
3782 EnterCriticalSection(&session->cs);
3783 session_set_sink_stream_state(session, (IMFStreamSink *)event_source, event_type);
3784 LeaveCriticalSection(&session->cs);
3786 break;
3787 case MEStreamSinkMarker:
3789 EnterCriticalSection(&session->cs);
3790 session_sink_stream_marker(session, (IMFStreamSink *)event_source);
3791 LeaveCriticalSection(&session->cs);
3793 break;
3794 case MEStreamSinkRequestSample:
3796 EnterCriticalSection(&session->cs);
3797 session_request_sample(session, (IMFStreamSink *)event_source);
3798 LeaveCriticalSection(&session->cs);
3800 break;
3801 case MEStreamSinkScrubSampleComplete:
3803 EnterCriticalSection(&session->cs);
3804 session_sink_stream_scrub_complete(session, (IMFStreamSink *)event_source);
3805 LeaveCriticalSection(&session->cs);
3806 break;
3807 case MEMediaSample:
3809 EnterCriticalSection(&session->cs);
3810 session_deliver_sample(session, (IMFMediaStream *)event_source, &value);
3811 LeaveCriticalSection(&session->cs);
3813 break;
3814 case MEEndOfStream:
3816 EnterCriticalSection(&session->cs);
3817 session_handle_end_of_stream(session, (IMFMediaStream *)event_source);
3818 LeaveCriticalSection(&session->cs);
3820 break;
3822 case MEEndOfPresentation:
3824 EnterCriticalSection(&session->cs);
3825 session_handle_end_of_presentation(session, (IMFMediaSource *)event_source);
3826 LeaveCriticalSection(&session->cs);
3828 break;
3829 case MEAudioSessionGroupingParamChanged:
3830 case MEAudioSessionIconChanged:
3831 case MEAudioSessionNameChanged:
3832 case MEAudioSessionVolumeChanged:
3834 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3836 break;
3837 case MEAudioSessionDeviceRemoved:
3838 case MEAudioSessionDisconnected:
3839 case MEAudioSessionExclusiveModeOverride:
3840 case MEAudioSessionFormatChanged:
3841 case MEAudioSessionServerShutdown:
3843 IMFMediaEventQueue_QueueEvent(session->event_queue, event);
3844 /* fallthrough */
3845 case MESinkInvalidated:
3847 EnterCriticalSection(&session->cs);
3848 session_sink_invalidated(session, event_type == MESinkInvalidated ? event : NULL,
3849 (IMFStreamSink *)event_source);
3850 LeaveCriticalSection(&session->cs);
3852 break;
3853 case MEQualityNotify:
3855 if (session->quality_manager)
3857 if (FAILED(IMFMediaEventGenerator_QueryInterface(event_source, &IID_IMFStreamSink, (void **)&object)))
3858 IMFMediaEventGenerator_QueryInterface(event_source, &IID_IMFTransform, (void **)&object);
3860 if (object)
3862 IMFQualityManager_NotifyQualityEvent(session->quality_manager, object, event);
3863 IUnknown_Release(object);
3867 break;
3868 default:
3872 PropVariantClear(&value);
3874 failed:
3875 if (event)
3876 IMFMediaEvent_Release(event);
3878 if (FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(event_source, iface, (IUnknown *)event_source)))
3879 WARN("Failed to re-subscribe, hr %#lx.\n", hr);
3881 IMFMediaEventGenerator_Release(event_source);
3883 return hr;
3886 static const IMFAsyncCallbackVtbl session_events_callback_vtbl =
3888 session_events_callback_QueryInterface,
3889 session_events_callback_AddRef,
3890 session_events_callback_Release,
3891 session_events_callback_GetParameters,
3892 session_events_callback_Invoke,
3895 static HRESULT WINAPI session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
3897 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
3898 IsEqualIID(riid, &IID_IUnknown))
3900 *obj = iface;
3901 IMFAsyncCallback_AddRef(iface);
3902 return S_OK;
3905 WARN("Unsupported %s.\n", debugstr_guid(riid));
3906 *obj = NULL;
3907 return E_NOINTERFACE;
3910 static ULONG WINAPI session_sink_finalizer_callback_AddRef(IMFAsyncCallback *iface)
3912 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3913 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3916 static ULONG WINAPI session_sink_finalizer_callback_Release(IMFAsyncCallback *iface)
3918 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3919 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
3922 static HRESULT WINAPI session_sink_finalizer_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
3924 return E_NOTIMPL;
3927 static HRESULT WINAPI session_sink_finalizer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
3929 struct media_session *session = impl_from_sink_finalizer_callback_IMFAsyncCallback(iface);
3930 IMFFinalizableMediaSink *fin_sink = NULL;
3931 BOOL sinks_finalized = TRUE;
3932 struct media_sink *sink;
3933 IUnknown *state;
3934 HRESULT hr;
3936 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
3937 return hr;
3939 EnterCriticalSection(&session->cs);
3941 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
3943 if (state == sink->object)
3945 if (FAILED(hr = IMFMediaSink_QueryInterface(sink->sink, &IID_IMFFinalizableMediaSink, (void **)&fin_sink)))
3946 WARN("Unexpected, missing IMFFinalizableMediaSink, hr %#lx.\n", hr);
3948 else
3950 sinks_finalized &= sink->finalized;
3951 if (!sinks_finalized)
3952 break;
3956 IUnknown_Release(state);
3958 if (fin_sink)
3960 /* Complete session transition, or close prematurely on error. */
3961 if (SUCCEEDED(hr = IMFFinalizableMediaSink_EndFinalize(fin_sink, result)))
3963 sink->finalized = TRUE;
3964 if (sinks_finalized)
3965 session_set_closed(session, hr);
3967 IMFFinalizableMediaSink_Release(fin_sink);
3970 LeaveCriticalSection(&session->cs);
3972 return S_OK;
3975 static const IMFAsyncCallbackVtbl session_sink_finalizer_callback_vtbl =
3977 session_sink_finalizer_callback_QueryInterface,
3978 session_sink_finalizer_callback_AddRef,
3979 session_sink_finalizer_callback_Release,
3980 session_sink_finalizer_callback_GetParameters,
3981 session_sink_finalizer_callback_Invoke,
3984 static HRESULT WINAPI session_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
3986 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3987 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
3990 static ULONG WINAPI session_rate_support_AddRef(IMFRateSupport *iface)
3992 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3993 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
3996 static ULONG WINAPI session_rate_support_Release(IMFRateSupport *iface)
3998 struct media_session *session = impl_session_from_IMFRateSupport(iface);
3999 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
4002 static HRESULT session_presentation_object_get_rate(IUnknown *object, MFRATE_DIRECTION direction,
4003 BOOL thin, BOOL fastest, float *result)
4005 IMFRateSupport *rate_support;
4006 float rate;
4007 HRESULT hr;
4009 /* For objects that don't support rate control, it's assumed that only forward direction is allowed, at 1.0f. */
4011 if (FAILED(hr = MFGetService(object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support)))
4013 if (direction == MFRATE_FORWARD)
4015 *result = 1.0f;
4016 return S_OK;
4018 else
4019 return MF_E_REVERSE_UNSUPPORTED;
4022 rate = 0.0f;
4023 if (fastest)
4025 if (SUCCEEDED(hr = IMFRateSupport_GetFastestRate(rate_support, direction, thin, &rate)))
4026 *result = min(fabsf(rate), *result);
4028 else
4030 if (SUCCEEDED(hr = IMFRateSupport_GetSlowestRate(rate_support, direction, thin, &rate)))
4031 *result = max(fabsf(rate), *result);
4034 IMFRateSupport_Release(rate_support);
4036 return hr;
4039 static HRESULT session_get_presentation_rate(struct media_session *session, MFRATE_DIRECTION direction,
4040 BOOL thin, BOOL fastest, float *result)
4042 struct media_source *source;
4043 struct media_sink *sink;
4044 HRESULT hr = E_POINTER;
4045 float rate;
4047 rate = fastest ? FLT_MAX : 0.0f;
4049 EnterCriticalSection(&session->cs);
4051 if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID)
4053 LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
4055 if (FAILED(hr = session_presentation_object_get_rate(source->object, direction, thin, fastest, &rate)))
4056 break;
4059 if (SUCCEEDED(hr))
4061 LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
4063 if (FAILED(hr = session_presentation_object_get_rate(sink->object, direction, thin, fastest, &rate)))
4064 break;
4069 LeaveCriticalSection(&session->cs);
4071 if (SUCCEEDED(hr))
4072 *result = direction == MFRATE_FORWARD ? rate : -rate;
4074 return hr;
4077 static HRESULT WINAPI session_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
4078 BOOL thin, float *rate)
4080 struct media_session *session = impl_session_from_IMFRateSupport(iface);
4082 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
4084 return session_get_presentation_rate(session, direction, thin, FALSE, rate);
4087 static HRESULT WINAPI session_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
4088 BOOL thin, float *rate)
4090 struct media_session *session = impl_session_from_IMFRateSupport(iface);
4092 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
4094 return session_get_presentation_rate(session, direction, thin, TRUE, rate);
4097 static HRESULT WINAPI session_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
4098 float *nearest_supported_rate)
4100 struct media_session *session = impl_session_from_IMFRateSupport(iface);
4101 HRESULT hr;
4103 TRACE("%p, %d, %f, %p.\n", iface, thin, rate, nearest_supported_rate);
4105 EnterCriticalSection(&session->cs);
4106 hr = session_is_presentation_rate_supported(session, thin, rate, nearest_supported_rate);
4107 LeaveCriticalSection(&session->cs);
4109 return hr;
4112 static const IMFRateSupportVtbl session_rate_support_vtbl =
4114 session_rate_support_QueryInterface,
4115 session_rate_support_AddRef,
4116 session_rate_support_Release,
4117 session_rate_support_GetSlowestRate,
4118 session_rate_support_GetFastestRate,
4119 session_rate_support_IsRateSupported,
4122 static HRESULT WINAPI session_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj)
4124 struct media_session *session = impl_session_from_IMFRateControl(iface);
4125 return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj);
4128 static ULONG WINAPI session_rate_control_AddRef(IMFRateControl *iface)
4130 struct media_session *session = impl_session_from_IMFRateControl(iface);
4131 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
4134 static ULONG WINAPI session_rate_control_Release(IMFRateControl *iface)
4136 struct media_session *session = impl_session_from_IMFRateControl(iface);
4137 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
4140 static HRESULT WINAPI session_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate)
4142 struct media_session *session = impl_session_from_IMFRateControl(iface);
4143 struct session_op *op;
4144 HRESULT hr;
4146 TRACE("%p, %d, %f.\n", iface, thin, rate);
4148 if (FAILED(hr = create_session_op(SESSION_CMD_SET_RATE, &op)))
4149 return hr;
4151 op->set_rate.thin = thin;
4152 op->set_rate.rate = rate;
4153 hr = session_submit_command(session, op);
4154 IUnknown_Release(&op->IUnknown_iface);
4155 return hr;
4158 static HRESULT WINAPI session_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
4160 struct media_session *session = impl_session_from_IMFRateControl(iface);
4162 TRACE("%p, %p, %p.\n", iface, thin, rate);
4164 return IMFRateControl_GetRate(session->clock_rate_control, thin, rate);
4167 static const IMFRateControlVtbl session_rate_control_vtbl =
4169 session_rate_control_QueryInterface,
4170 session_rate_control_AddRef,
4171 session_rate_control_Release,
4172 session_rate_control_SetRate,
4173 session_rate_control_GetRate,
4176 static HRESULT WINAPI node_attribute_editor_QueryInterface(IMFTopologyNodeAttributeEditor *iface,
4177 REFIID riid, void **obj)
4179 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
4181 if (IsEqualIID(riid, &IID_IMFTopologyNodeAttributeEditor) ||
4182 IsEqualIID(riid, &IID_IUnknown))
4184 *obj = iface;
4185 IMFTopologyNodeAttributeEditor_AddRef(iface);
4186 return S_OK;
4189 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
4190 *obj = NULL;
4191 return E_NOINTERFACE;
4194 static ULONG WINAPI node_attribute_editor_AddRef(IMFTopologyNodeAttributeEditor *iface)
4196 struct media_session *session = impl_session_from_IMFTopologyNodeAttributeEditor(iface);
4197 return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
4200 static ULONG WINAPI node_attribute_editor_Release(IMFTopologyNodeAttributeEditor *iface)
4202 struct media_session *session = impl_session_from_IMFTopologyNodeAttributeEditor(iface);
4203 return IMFMediaSession_Release(&session->IMFMediaSession_iface);
4206 static HRESULT WINAPI node_attribute_editor_UpdateNodeAttributes(IMFTopologyNodeAttributeEditor *iface,
4207 TOPOID id, DWORD count, MFTOPONODE_ATTRIBUTE_UPDATE *updates)
4209 FIXME("%p, %s, %lu, %p.\n", iface, wine_dbgstr_longlong(id), count, updates);
4211 return E_NOTIMPL;
4214 static const IMFTopologyNodeAttributeEditorVtbl node_attribute_editor_vtbl =
4216 node_attribute_editor_QueryInterface,
4217 node_attribute_editor_AddRef,
4218 node_attribute_editor_Release,
4219 node_attribute_editor_UpdateNodeAttributes,
4222 /***********************************************************************
4223 * MFCreateMediaSession (mf.@)
4225 HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **session)
4227 BOOL without_quality_manager = FALSE;
4228 struct media_session *object;
4229 HRESULT hr;
4231 TRACE("%p, %p.\n", config, session);
4233 if (!(object = calloc(1, sizeof(*object))))
4234 return E_OUTOFMEMORY;
4236 object->IMFMediaSession_iface.lpVtbl = &mfmediasessionvtbl;
4237 object->IMFGetService_iface.lpVtbl = &session_get_service_vtbl;
4238 object->IMFRateSupport_iface.lpVtbl = &session_rate_support_vtbl;
4239 object->IMFRateControl_iface.lpVtbl = &session_rate_control_vtbl;
4240 object->IMFTopologyNodeAttributeEditor_iface.lpVtbl = &node_attribute_editor_vtbl;
4241 object->commands_callback.lpVtbl = &session_commands_callback_vtbl;
4242 object->sa_ready_callback.lpVtbl = &session_sa_ready_callback_vtbl;
4243 object->events_callback.lpVtbl = &session_events_callback_vtbl;
4244 object->sink_finalizer_callback.lpVtbl = &session_sink_finalizer_callback_vtbl;
4245 object->refcount = 1;
4246 list_init(&object->topologies);
4247 list_init(&object->commands);
4248 list_init(&object->presentation.sources);
4249 list_init(&object->presentation.sinks);
4250 list_init(&object->presentation.nodes);
4251 InitializeCriticalSection(&object->cs);
4253 if (FAILED(hr = MFCreateTopology(&object->presentation.current_topology)))
4254 goto failed;
4256 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
4257 goto failed;
4259 if (FAILED(hr = MFCreatePresentationClock(&object->clock)))
4260 goto failed;
4262 if (FAILED(hr = MFCreateSystemTimeSource(&object->system_time_source)))
4263 goto failed;
4265 if (FAILED(hr = IMFPresentationClock_QueryInterface(object->clock, &IID_IMFRateControl,
4266 (void **)&object->clock_rate_control)))
4268 goto failed;
4271 if (config)
4273 GUID clsid;
4275 if (SUCCEEDED(IMFAttributes_GetGUID(config, &MF_SESSION_TOPOLOADER, &clsid)))
4277 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTopoLoader,
4278 (void **)&object->topo_loader)))
4280 WARN("Failed to create custom topology loader, hr %#lx.\n", hr);
4284 if (SUCCEEDED(IMFAttributes_GetGUID(config, &MF_SESSION_QUALITY_MANAGER, &clsid)))
4286 if (!(without_quality_manager = IsEqualGUID(&clsid, &GUID_NULL)))
4288 if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFQualityManager,
4289 (void **)&object->quality_manager)))
4291 WARN("Failed to create custom quality manager, hr %#lx.\n", hr);
4297 if (!object->topo_loader && FAILED(hr = MFCreateTopoLoader(&object->topo_loader)))
4298 goto failed;
4300 if (!object->quality_manager && !without_quality_manager &&
4301 FAILED(hr = MFCreateStandardQualityManager(&object->quality_manager)))
4303 goto failed;
4306 if (object->quality_manager && FAILED(hr = IMFQualityManager_NotifyPresentationClock(object->quality_manager,
4307 object->clock)))
4309 goto failed;
4312 *session = &object->IMFMediaSession_iface;
4314 return S_OK;
4316 failed:
4317 IMFMediaSession_Release(&object->IMFMediaSession_iface);
4318 return hr;