[PATCH 2/2] mf: Implement initial support for starting media sources within a session.
Nikolay Sivov
nsivov at codeweavers.com
Tue Oct 1 08:35:33 CDT 2019
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/mf/session.c | 196 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 188 insertions(+), 8 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index c1daef3a91..02e24a2305 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -37,6 +37,7 @@ enum session_command
SESSION_CMD_CLEAR_TOPOLOGIES,
SESSION_CMD_CLOSE,
SESSION_CMD_SET_TOPOLOGY,
+ SESSION_CMD_START,
};
struct session_op
@@ -51,6 +52,11 @@ struct session_op
DWORD flags;
IMFTopology *topology;
} set_topology;
+ struct
+ {
+ GUID time_format;
+ PROPVARIANT start_position;
+ } start;
} u;
};
@@ -63,6 +69,8 @@ struct queued_topology
enum session_state
{
SESSION_STATE_STOPPED = 0,
+ SESSION_STATE_STARTING,
+ SESSION_STATE_RUNNING,
SESSION_STATE_CLOSED,
SESSION_STATE_SHUT_DOWN,
};
@@ -74,6 +82,7 @@ struct media_session
IMFRateSupport IMFRateSupport_iface;
IMFRateControl IMFRateControl_iface;
IMFAsyncCallback commands_callback;
+ IMFAsyncCallback events_callback;
LONG refcount;
IMFMediaEventQueue *event_queue;
IMFPresentationClock *clock;
@@ -161,6 +170,11 @@ static struct media_session *impl_from_commands_callback_IMFAsyncCallback(IMFAsy
return CONTAINING_RECORD(iface, struct media_session, commands_callback);
}
+static struct media_session *impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
+{
+ return CONTAINING_RECORD(iface, struct media_session, events_callback);
+}
+
static struct media_session *impl_from_IMFGetService(IMFGetService *iface)
{
return CONTAINING_RECORD(iface, struct media_session, IMFGetService_iface);
@@ -248,10 +262,17 @@ static ULONG WINAPI session_op_Release(IUnknown *iface)
if (!refcount)
{
- if (op->command == SESSION_CMD_SET_TOPOLOGY)
+ switch (op->command)
{
- if (op->u.set_topology.topology)
- IMFTopology_Release(op->u.set_topology.topology);
+ case SESSION_CMD_SET_TOPOLOGY:
+ if (op->u.set_topology.topology)
+ IMFTopology_Release(op->u.set_topology.topology);
+ break;
+ case SESSION_CMD_START:
+ PropVariantClear(&op->u.start.start_position);
+ break;
+ default:
+ ;
}
heap_free(op);
}
@@ -270,7 +291,7 @@ static HRESULT create_session_op(enum session_command command, struct session_op
{
struct session_op *op;
- if (!(op = heap_alloc(sizeof(*op))))
+ if (!(op = heap_alloc_zero(sizeof(*op))))
return E_OUTOFMEMORY;
op->IUnknown_iface.lpVtbl = &session_op_vtbl;
@@ -330,7 +351,7 @@ static HRESULT session_bind_output_nodes(IMFTopology *topology)
if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type)) || node_type != MF_TOPOLOGY_OUTPUT_NODE)
{
IMFTopologyNode_Release(node);
- break;
+ continue;
}
if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object)))
@@ -370,6 +391,92 @@ static HRESULT session_bind_output_nodes(IMFTopology *topology)
return hr;
}
+static IMFTopology *session_get_next_topology(struct media_session *session)
+{
+ struct queued_topology *queued;
+
+ if (!session->current_topology)
+ {
+ struct list *head = list_head(&session->topologies);
+ if (!head)
+ return NULL;
+
+ queued = LIST_ENTRY(head, struct queued_topology, entry);
+ session->current_topology = queued->topology;
+ list_remove(&queued->entry);
+ heap_free(queued);
+ }
+
+ return session->current_topology;
+}
+
+static void session_start(struct media_session *session, const GUID *time_format, const PROPVARIANT *start_position)
+{
+ IMFTopologyNode *node;
+ IMFTopology *topology;
+ IMFCollection *nodes;
+ DWORD count, i;
+ HRESULT hr;
+
+ EnterCriticalSection(&session->cs);
+
+ switch (session->state)
+ {
+ case SESSION_STATE_STOPPED:
+ topology = session_get_next_topology(session);
+
+ if (!topology || FAILED(IMFTopology_GetSourceNodeCollection(topology, &nodes)))
+ break;
+
+ if (FAILED(IMFCollection_GetElementCount(nodes, &count)))
+ break;
+
+ for (i = 0; i < count; ++i)
+ {
+ if (SUCCEEDED(IMFCollection_GetElement(nodes, i, (IUnknown **)&node)))
+ {
+ IMFPresentationDescriptor *pd = NULL;
+ IMFMediaSource *source = NULL;
+
+ hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_SOURCE, &IID_IMFMediaSource,
+ (void **)&source);
+
+ if (SUCCEEDED(hr))
+ hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR,
+ &IID_IMFPresentationDescriptor, (void **)&pd);
+
+ /* Subscribe to source events, start it. */
+ if (SUCCEEDED(hr))
+ hr = IMFMediaSource_BeginGetEvent(source, &session->events_callback, NULL);
+
+ if (SUCCEEDED(hr))
+ hr = IMFMediaSource_Start(source, pd, time_format, start_position);
+
+ if (source)
+ IMFMediaSource_Release(source);
+
+ if (pd)
+ IMFPresentationDescriptor_Release(pd);
+
+ IMFTopologyNode_Release(node);
+ }
+ }
+
+ session->state = SESSION_STATE_STARTING;
+
+ IMFCollection_Release(nodes);
+
+ break;
+ case SESSION_STATE_RUNNING:
+ FIXME("Seeking is not implemented.\n");
+ break;
+ default:
+ ;
+ }
+
+ LeaveCriticalSection(&session->cs);
+}
+
static HRESULT WINAPI mfsession_QueryInterface(IMFMediaSession *iface, REFIID riid, void **out)
{
struct media_session *session = impl_from_IMFMediaSession(iface);
@@ -518,11 +625,29 @@ static HRESULT WINAPI mfsession_ClearTopologies(IMFMediaSession *iface)
return hr;
}
-static HRESULT WINAPI mfsession_Start(IMFMediaSession *iface, const GUID *format, const PROPVARIANT *start)
+static HRESULT WINAPI mfsession_Start(IMFMediaSession *iface, const GUID *format, const PROPVARIANT *start_position)
{
- FIXME("(%p)->(%s, %p)\n", iface, debugstr_guid(format), start);
+ struct media_session *session = impl_from_IMFMediaSession(iface);
+ struct session_op *op;
+ HRESULT hr;
- return E_NOTIMPL;
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), start_position);
+
+ if (!start_position)
+ return E_POINTER;
+
+ if (FAILED(hr = create_session_op(SESSION_CMD_START, &op)))
+ return hr;
+
+ op->u.start.time_format = format ? *format : GUID_NULL;
+ hr = PropVariantCopy(&op->u.start.start_position, start_position);
+
+ if (SUCCEEDED(hr))
+ hr = session_submit_command(session, op);
+
+ IUnknown_Release(&op->IUnknown_iface);
+
+ return hr;
}
static HRESULT WINAPI mfsession_Pause(IMFMediaSession *iface)
@@ -765,7 +890,10 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface,
status = IMFTopoLoader_Load(session->topo_loader, topology, &resolved_topology, NULL /* FIXME? */);
if (SUCCEEDED(status))
+ {
topology = resolved_topology;
+ topo_status = MF_TOPOSTATUS_READY;
+ }
}
if (SUCCEEDED(status))
@@ -819,6 +947,11 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface,
break;
}
+ case SESSION_CMD_START:
+ {
+ session_start(session, &op->u.start.time_format, &op->u.start.start_position);
+ break;
+ }
case SESSION_CMD_CLOSE:
EnterCriticalSection(&session->cs);
if (session->state != SESSION_STATE_CLOSED)
@@ -845,6 +978,52 @@ static const IMFAsyncCallbackVtbl session_commands_callback_vtbl =
session_commands_callback_Invoke,
};
+static HRESULT WINAPI session_events_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
+{
+ if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = iface;
+ IMFAsyncCallback_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI session_events_callback_AddRef(IMFAsyncCallback *iface)
+{
+ struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
+ return IMFMediaSession_AddRef(&session->IMFMediaSession_iface);
+}
+
+static ULONG WINAPI session_events_callback_Release(IMFAsyncCallback *iface)
+{
+ struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
+ return IMFMediaSession_Release(&session->IMFMediaSession_iface);
+}
+
+static HRESULT WINAPI session_events_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
+{
+ return S_OK;
+}
+
+static const IMFAsyncCallbackVtbl session_events_callback_vtbl =
+{
+ session_events_callback_QueryInterface,
+ session_events_callback_AddRef,
+ session_events_callback_Release,
+ session_events_callback_GetParameters,
+ session_events_callback_Invoke,
+};
+
static HRESULT WINAPI session_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
{
struct media_session *session = impl_session_from_IMFRateSupport(iface);
@@ -960,6 +1139,7 @@ HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **ses
object->IMFRateSupport_iface.lpVtbl = &session_rate_support_vtbl;
object->IMFRateControl_iface.lpVtbl = &session_rate_control_vtbl;
object->commands_callback.lpVtbl = &session_commands_callback_vtbl;
+ object->events_callback.lpVtbl = &session_events_callback_vtbl;
object->refcount = 1;
list_init(&object->topologies);
InitializeCriticalSection(&object->cs);
--
2.23.0
More information about the wine-devel
mailing list