mf: Add initial async implementation of SetTopology().
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
e578ee3b0a
commit
d2bd44992e
|
@ -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;
|
||||
|
||||
queued_topology->topology = topology;
|
||||
IMFTopology_AddRef(queued_topology->topology);
|
||||
|
||||
EnterCriticalSection(&session->cs);
|
||||
list_add_tail(&session->topologies, &queued_topology->entry);
|
||||
LeaveCriticalSection(&session->cs);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT session_submit_command(struct media_session *session, IUnknown *op)
|
||||
{
|
||||
struct session_op *op;
|
||||
WORD node_count = 0;
|
||||
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);
|
||||
LeaveCriticalSection(&session->cs);
|
||||
TRACE("%p, %#x, %p.\n", iface, flags, topology);
|
||||
|
||||
if (topology)
|
||||
{
|
||||
if (FAILED(IMFTopology_GetNodeCount(topology, &node_count)) || node_count == 0)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (FAILED(hr = create_session_op(SESSION_CMD_SET_TOPOLOGY, &op)))
|
||||
return 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);
|
||||
|
||||
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)
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue