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_CLEAR_TOPOLOGIES,
|
||||||
SESSION_CMD_CLOSE,
|
SESSION_CMD_CLOSE,
|
||||||
|
SESSION_CMD_SET_TOPOLOGY,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct session_op
|
struct session_op
|
||||||
|
@ -43,6 +44,14 @@ struct session_op
|
||||||
IUnknown IUnknown_iface;
|
IUnknown IUnknown_iface;
|
||||||
LONG refcount;
|
LONG refcount;
|
||||||
enum session_command command;
|
enum session_command command;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
DWORD flags;
|
||||||
|
IMFTopology *topology;
|
||||||
|
} set_topology;
|
||||||
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct queued_topology
|
struct queued_topology
|
||||||
|
@ -71,6 +80,7 @@ struct media_session
|
||||||
IMFRateControl *clock_rate_control;
|
IMFRateControl *clock_rate_control;
|
||||||
IMFTopoLoader *topo_loader;
|
IMFTopoLoader *topo_loader;
|
||||||
IMFQualityManager *quality_manager;
|
IMFQualityManager *quality_manager;
|
||||||
|
IMFTopology *current_topology;
|
||||||
struct list topologies;
|
struct list topologies;
|
||||||
enum session_state state;
|
enum session_state state;
|
||||||
CRITICAL_SECTION cs;
|
CRITICAL_SECTION cs;
|
||||||
|
@ -238,6 +248,11 @@ static ULONG WINAPI session_op_Release(IUnknown *iface)
|
||||||
|
|
||||||
if (!refcount)
|
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);
|
heap_free(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,7 +266,7 @@ static IUnknownVtbl session_op_vtbl =
|
||||||
session_op_Release,
|
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;
|
struct session_op *op;
|
||||||
|
|
||||||
|
@ -262,11 +277,25 @@ static HRESULT create_session_op(enum session_command command, IUnknown **ret)
|
||||||
op->refcount = 1;
|
op->refcount = 1;
|
||||||
op->command = command;
|
op->command = command;
|
||||||
|
|
||||||
*ret = &op->IUnknown_iface;
|
*ret = op;
|
||||||
|
|
||||||
return S_OK;
|
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)
|
static void session_clear_topologies(struct media_session *session)
|
||||||
{
|
{
|
||||||
struct queued_topology *ptr, *next;
|
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)
|
static HRESULT WINAPI mfsession_QueryInterface(IMFMediaSession *iface, REFIID riid, void **out)
|
||||||
{
|
{
|
||||||
struct media_session *session = impl_from_IMFMediaSession(iface);
|
struct media_session *session = impl_from_IMFMediaSession(iface);
|
||||||
|
@ -325,6 +416,8 @@ static ULONG WINAPI mfsession_Release(IMFMediaSession *iface)
|
||||||
if (!refcount)
|
if (!refcount)
|
||||||
{
|
{
|
||||||
session_clear_topologies(session);
|
session_clear_topologies(session);
|
||||||
|
if (session->current_topology)
|
||||||
|
IMFTopology_Release(session->current_topology);
|
||||||
if (session->event_queue)
|
if (session->event_queue)
|
||||||
IMFMediaEventQueue_Release(session->event_queue);
|
IMFMediaEventQueue_Release(session->event_queue);
|
||||||
if (session->clock)
|
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)
|
static HRESULT WINAPI mfsession_SetTopology(IMFMediaSession *iface, DWORD flags, IMFTopology *topology)
|
||||||
{
|
{
|
||||||
struct media_session *session = impl_from_IMFMediaSession(iface);
|
struct media_session *session = impl_from_IMFMediaSession(iface);
|
||||||
struct queued_topology *queued_topology;
|
struct session_op *op;
|
||||||
|
WORD node_count = 0;
|
||||||
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)
|
|
||||||
{
|
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
EnterCriticalSection(&session->cs);
|
TRACE("%p, %#x, %p.\n", iface, flags, topology);
|
||||||
if (session->state == SESSION_STATE_SHUT_DOWN)
|
|
||||||
hr = MF_E_SHUTDOWN;
|
if (topology)
|
||||||
else
|
{
|
||||||
hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, op);
|
if (FAILED(IMFTopology_GetNodeCount(topology, &node_count)) || node_count == 0)
|
||||||
LeaveCriticalSection(&session->cs);
|
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;
|
return hr;
|
||||||
}
|
}
|
||||||
|
@ -416,7 +504,7 @@ static HRESULT session_submit_command(struct media_session *session, IUnknown *o
|
||||||
static HRESULT WINAPI mfsession_ClearTopologies(IMFMediaSession *iface)
|
static HRESULT WINAPI mfsession_ClearTopologies(IMFMediaSession *iface)
|
||||||
{
|
{
|
||||||
struct media_session *session = impl_from_IMFMediaSession(iface);
|
struct media_session *session = impl_from_IMFMediaSession(iface);
|
||||||
IUnknown *op;
|
struct session_op *op;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
TRACE("%p.\n", iface);
|
TRACE("%p.\n", iface);
|
||||||
|
@ -425,7 +513,7 @@ static HRESULT WINAPI mfsession_ClearTopologies(IMFMediaSession *iface)
|
||||||
return hr;
|
return hr;
|
||||||
|
|
||||||
hr = session_submit_command(session, op);
|
hr = session_submit_command(session, op);
|
||||||
IUnknown_Release(op);
|
IUnknown_Release(&op->IUnknown_iface);
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
@ -454,7 +542,7 @@ static HRESULT WINAPI mfsession_Stop(IMFMediaSession *iface)
|
||||||
static HRESULT WINAPI mfsession_Close(IMFMediaSession *iface)
|
static HRESULT WINAPI mfsession_Close(IMFMediaSession *iface)
|
||||||
{
|
{
|
||||||
struct media_session *session = impl_from_IMFMediaSession(iface);
|
struct media_session *session = impl_from_IMFMediaSession(iface);
|
||||||
IUnknown *op;
|
struct session_op *op;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
TRACE("(%p)\n", iface);
|
TRACE("(%p)\n", iface);
|
||||||
|
@ -463,7 +551,7 @@ static HRESULT WINAPI mfsession_Close(IMFMediaSession *iface)
|
||||||
return hr;
|
return hr;
|
||||||
|
|
||||||
hr = session_submit_command(session, op);
|
hr = session_submit_command(session, op);
|
||||||
IUnknown_Release(op);
|
IUnknown_Release(&op->IUnknown_iface);
|
||||||
|
|
||||||
return hr;
|
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 session_op *op = impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result));
|
||||||
struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
|
struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
|
||||||
|
HRESULT status = S_OK;
|
||||||
|
|
||||||
switch (op->command)
|
switch (op->command)
|
||||||
{
|
{
|
||||||
|
@ -638,6 +727,98 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface,
|
||||||
IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologiesCleared, &GUID_NULL,
|
IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologiesCleared, &GUID_NULL,
|
||||||
S_OK, NULL);
|
S_OK, NULL);
|
||||||
break;
|
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:
|
case SESSION_CMD_CLOSE:
|
||||||
EnterCriticalSection(&session->cs);
|
EnterCriticalSection(&session->cs);
|
||||||
if (session->state != SESSION_STATE_CLOSED)
|
if (session->state != SESSION_STATE_CLOSED)
|
||||||
|
|
|
@ -370,6 +370,16 @@ enum _MFT_ENUM_FLAG
|
||||||
MFT_ENUM_FLAG_UNTRUSTED_STOREMFT = 0x00000400,
|
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 MFAddPeriodicCallback(MFPERIODICCALLBACK callback, IUnknown *context, DWORD *key);
|
||||||
HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue);
|
HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue);
|
||||||
HRESULT WINAPI MFAllocateWorkQueueEx(MFASYNC_WORKQUEUE_TYPE queue_type, DWORD *queue);
|
HRESULT WINAPI MFAllocateWorkQueueEx(MFASYNC_WORKQUEUE_TYPE queue_type, DWORD *queue);
|
||||||
|
|
Loading…
Reference in New Issue