[PATCH 2/2] mf: Add initial async implementation of SetTopology().
Nikolay Sivov
nsivov at codeweavers.com
Fri Sep 27 06:28:31 CDT 2019
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/mf/session.c | 237 ++++++++++++++++++++++++++++++++++++++++------
include/mfapi.h | 10 ++
2 files changed, 219 insertions(+), 28 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index 6fdf773702..c1daef3a91 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -36,6 +36,7 @@ enum session_command
{
SESSION_CMD_CLEAR_TOPOLOGIES,
SESSION_CMD_CLOSE,
+ SESSION_CMD_SET_TOPOLOGY,
};
struct session_op
@@ -43,6 +44,14 @@ struct session_op
IUnknown IUnknown_iface;
LONG refcount;
enum session_command command;
+ union
+ {
+ struct
+ {
+ DWORD flags;
+ IMFTopology *topology;
+ } set_topology;
+ } u;
};
struct queued_topology
@@ -71,6 +80,7 @@ struct media_session
IMFRateControl *clock_rate_control;
IMFTopoLoader *topo_loader;
IMFQualityManager *quality_manager;
+ IMFTopology *current_topology;
struct list topologies;
enum session_state state;
CRITICAL_SECTION cs;
@@ -238,6 +248,11 @@ static ULONG WINAPI session_op_Release(IUnknown *iface)
if (!refcount)
{
+ if (op->command == SESSION_CMD_SET_TOPOLOGY)
+ {
+ if (op->u.set_topology.topology)
+ IMFTopology_Release(op->u.set_topology.topology);
+ }
heap_free(op);
}
@@ -251,7 +266,7 @@ static IUnknownVtbl session_op_vtbl =
session_op_Release,
};
-static HRESULT create_session_op(enum session_command command, IUnknown **ret)
+static HRESULT create_session_op(enum session_command command, struct session_op **ret)
{
struct session_op *op;
@@ -262,11 +277,25 @@ static HRESULT create_session_op(enum session_command command, IUnknown **ret)
op->refcount = 1;
op->command = command;
- *ret = &op->IUnknown_iface;
+ *ret = op;
return S_OK;
}
+static HRESULT session_submit_command(struct media_session *session, struct session_op *op)
+{
+ HRESULT hr;
+
+ EnterCriticalSection(&session->cs);
+ if (session->state == SESSION_STATE_SHUT_DOWN)
+ hr = MF_E_SHUTDOWN;
+ else
+ hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface);
+ LeaveCriticalSection(&session->cs);
+
+ return hr;
+}
+
static void session_clear_topologies(struct media_session *session)
{
struct queued_topology *ptr, *next;
@@ -279,6 +308,68 @@ static void session_clear_topologies(struct media_session *session)
}
}
+static HRESULT session_bind_output_nodes(IMFTopology *topology)
+{
+ MF_TOPOLOGY_TYPE node_type;
+ IMFStreamSink *stream_sink;
+ IMFMediaSink *media_sink;
+ WORD node_count = 0, i;
+ IMFTopologyNode *node;
+ IMFActivate *activate;
+ UINT32 stream_id;
+ IUnknown *object;
+ HRESULT hr;
+
+ hr = IMFTopology_GetNodeCount(topology, &node_count);
+
+ for (i = 0; i < node_count; ++i)
+ {
+ if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
+ break;
+
+ if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type)) || node_type != MF_TOPOLOGY_OUTPUT_NODE)
+ {
+ IMFTopologyNode_Release(node);
+ break;
+ }
+
+ if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object)))
+ {
+ stream_sink = NULL;
+ if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&stream_sink)))
+ {
+ if (SUCCEEDED(hr = IUnknown_QueryInterface(object, &IID_IMFActivate, (void **)&activate)))
+ {
+ if (SUCCEEDED(hr = IMFActivate_ActivateObject(activate, &IID_IMFMediaSink, (void **)&media_sink)))
+ {
+ if (FAILED(IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_STREAMID, &stream_id)))
+ stream_id = 0;
+
+ stream_sink = NULL;
+ if (FAILED(IMFMediaSink_GetStreamSinkById(media_sink, stream_id, &stream_sink)))
+ hr = IMFMediaSink_AddStreamSink(media_sink, stream_id, NULL, &stream_sink);
+
+ if (stream_sink)
+ hr = IMFTopologyNode_SetObject(node, (IUnknown *)stream_sink);
+
+ IMFMediaSink_Release(media_sink);
+ }
+
+ IMFActivate_Release(activate);
+ }
+ }
+
+ if (stream_sink)
+ IMFStreamSink_Release(stream_sink);
+ IUnknown_Release(object);
+ }
+
+ IMFTopologyNode_Release(node);
+ }
+
+ return hr;
+}
+
static HRESULT WINAPI mfsession_QueryInterface(IMFMediaSession *iface, REFIID riid, void **out)
{
struct media_session *session = impl_from_IMFMediaSession(iface);
@@ -325,6 +416,8 @@ static ULONG WINAPI mfsession_Release(IMFMediaSession *iface)
if (!refcount)
{
session_clear_topologies(session);
+ if (session->current_topology)
+ IMFTopology_Release(session->current_topology);
if (session->event_queue)
IMFMediaEventQueue_Release(session->event_queue);
if (session->clock)
@@ -382,33 +475,28 @@ static HRESULT WINAPI mfsession_QueueEvent(IMFMediaSession *iface, MediaEventTyp
static HRESULT WINAPI mfsession_SetTopology(IMFMediaSession *iface, DWORD flags, IMFTopology *topology)
{
struct media_session *session = impl_from_IMFMediaSession(iface);
- struct queued_topology *queued_topology;
-
- FIXME("%p, %#x, %p.\n", iface, flags, topology);
-
- if (!(queued_topology = heap_alloc(sizeof(*queued_topology))))
- return E_OUTOFMEMORY;
+ struct session_op *op;
+ WORD node_count = 0;
+ HRESULT hr;
- queued_topology->topology = topology;
- IMFTopology_AddRef(queued_topology->topology);
+ TRACE("%p, %#x, %p.\n", iface, flags, topology);
- EnterCriticalSection(&session->cs);
- list_add_tail(&session->topologies, &queued_topology->entry);
- LeaveCriticalSection(&session->cs);
+ if (topology)
+ {
+ if (FAILED(IMFTopology_GetNodeCount(topology, &node_count)) || node_count == 0)
+ return E_INVALIDARG;
+ }
- return S_OK;
-}
+ if (FAILED(hr = create_session_op(SESSION_CMD_SET_TOPOLOGY, &op)))
+ return hr;
-static HRESULT session_submit_command(struct media_session *session, IUnknown *op)
-{
- HRESULT hr;
+ op->u.set_topology.flags = flags;
+ op->u.set_topology.topology = topology;
+ if (op->u.set_topology.topology)
+ IMFTopology_AddRef(op->u.set_topology.topology);
- EnterCriticalSection(&session->cs);
- if (session->state == SESSION_STATE_SHUT_DOWN)
- hr = MF_E_SHUTDOWN;
- else
- hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, op);
- LeaveCriticalSection(&session->cs);
+ hr = session_submit_command(session, op);
+ IUnknown_Release(&op->IUnknown_iface);
return hr;
}
@@ -416,7 +504,7 @@ static HRESULT session_submit_command(struct media_session *session, IUnknown *o
static HRESULT WINAPI mfsession_ClearTopologies(IMFMediaSession *iface)
{
struct media_session *session = impl_from_IMFMediaSession(iface);
- IUnknown *op;
+ struct session_op *op;
HRESULT hr;
TRACE("%p.\n", iface);
@@ -425,7 +513,7 @@ static HRESULT WINAPI mfsession_ClearTopologies(IMFMediaSession *iface)
return hr;
hr = session_submit_command(session, op);
- IUnknown_Release(op);
+ IUnknown_Release(&op->IUnknown_iface);
return hr;
}
@@ -454,7 +542,7 @@ static HRESULT WINAPI mfsession_Stop(IMFMediaSession *iface)
static HRESULT WINAPI mfsession_Close(IMFMediaSession *iface)
{
struct media_session *session = impl_from_IMFMediaSession(iface);
- IUnknown *op;
+ struct session_op *op;
HRESULT hr;
TRACE("(%p)\n", iface);
@@ -463,7 +551,7 @@ static HRESULT WINAPI mfsession_Close(IMFMediaSession *iface)
return hr;
hr = session_submit_command(session, op);
- IUnknown_Release(op);
+ IUnknown_Release(&op->IUnknown_iface);
return hr;
}
@@ -627,6 +715,7 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface,
{
struct session_op *op = impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result));
struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
+ HRESULT status = S_OK;
switch (op->command)
{
@@ -638,6 +727,98 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface,
IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologiesCleared, &GUID_NULL,
S_OK, NULL);
break;
+ case SESSION_CMD_SET_TOPOLOGY:
+ {
+ IMFTopology *topology = op->u.set_topology.topology;
+ MF_TOPOSTATUS topo_status = MF_TOPOSTATUS_INVALID;
+ struct queued_topology *queued_topology;
+ DWORD flags = op->u.set_topology.flags;
+ PROPVARIANT param;
+
+ if (flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT)
+ {
+ EnterCriticalSection(&session->cs);
+ if ((topology && topology == session->current_topology) || !topology)
+ {
+ /* FIXME: stop current topology, queue next one. */
+ if (session->current_topology)
+ {
+ IMFTopology_Release(session->current_topology);
+ session->current_topology = NULL;
+ }
+ }
+ else
+ status = S_FALSE;
+ topo_status = MF_TOPOSTATUS_READY;
+ LeaveCriticalSection(&session->cs);
+ }
+ else if (topology)
+ {
+ /* Resolve unless claimed to be full. */
+ if (!(flags & MFSESSION_SETTOPOLOGY_NORESOLUTION))
+ {
+ IMFTopology *resolved_topology = NULL;
+
+ status = session_bind_output_nodes(topology);
+
+ if (SUCCEEDED(status))
+ status = IMFTopoLoader_Load(session->topo_loader, topology, &resolved_topology, NULL /* FIXME? */);
+
+ if (SUCCEEDED(status))
+ topology = resolved_topology;
+ }
+
+ if (SUCCEEDED(status))
+ {
+ if (!(queued_topology = heap_alloc_zero(sizeof(*queued_topology))))
+ status = E_OUTOFMEMORY;
+ else
+ {
+ EnterCriticalSection(&session->cs);
+
+ if (flags & MFSESSION_SETTOPOLOGY_IMMEDIATE)
+ {
+ session_clear_topologies(session);
+ if (session->current_topology)
+ {
+ IMFTopology_Release(session->current_topology);
+ session->current_topology = NULL;
+ }
+ }
+
+ queued_topology->topology = topology;
+ IMFTopology_AddRef(queued_topology->topology);
+ list_add_tail(&session->topologies, &queued_topology->entry);
+
+ LeaveCriticalSection(&session->cs);
+ }
+ }
+ }
+
+ if (topology)
+ {
+ param.vt = VT_UNKNOWN;
+ param.punkVal = (IUnknown *)topology;
+ }
+ else
+ param.vt = VT_EMPTY;
+
+ IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologySet, &GUID_NULL,
+ status, ¶m);
+ if (topo_status != MF_TOPOSTATUS_INVALID)
+ {
+ IMFMediaEvent *event;
+
+ if (SUCCEEDED(MFCreateMediaEvent(MESessionTopologyStatus, &GUID_NULL, status, ¶m, &event)))
+ {
+ IMFMediaEvent_SetUINT32(event, &MF_EVENT_TOPOLOGY_STATUS, topo_status);
+ IMFMediaEventQueue_QueueEvent(session->event_queue, event);
+ IMFMediaEvent_Release(event);
+ }
+ }
+
+ break;
+ }
case SESSION_CMD_CLOSE:
EnterCriticalSection(&session->cs);
if (session->state != SESSION_STATE_CLOSED)
diff --git a/include/mfapi.h b/include/mfapi.h
index 1a8fa25d00..346bd38d92 100644
--- a/include/mfapi.h
+++ b/include/mfapi.h
@@ -370,6 +370,16 @@ enum _MFT_ENUM_FLAG
MFT_ENUM_FLAG_UNTRUSTED_STOREMFT = 0x00000400,
};
+typedef enum
+{
+ MF_TOPOSTATUS_INVALID = 0,
+ MF_TOPOSTATUS_READY = 100,
+ MF_TOPOSTATUS_STARTED_SOURCE = 200,
+ MF_TOPOSTATUS_DYNAMIC_CHANGED = 210,
+ MF_TOPOSTATUS_SINK_SWITCHED = 300,
+ MF_TOPOSTATUS_ENDED = 400,
+} MF_TOPOSTATUS;
+
HRESULT WINAPI MFAddPeriodicCallback(MFPERIODICCALLBACK callback, IUnknown *context, DWORD *key);
HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue);
HRESULT WINAPI MFAllocateWorkQueueEx(MFASYNC_WORKQUEUE_TYPE queue_type, DWORD *queue);
--
2.23.0
More information about the wine-devel
mailing list