mf: Use separate list for source streams.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
a93dde5ad8
commit
adb420ee0d
|
@ -79,12 +79,6 @@ enum session_state
|
|||
SESSION_STATE_SHUT_DOWN,
|
||||
};
|
||||
|
||||
struct media_stream
|
||||
{
|
||||
struct list entry;
|
||||
IMFMediaStream *stream;
|
||||
};
|
||||
|
||||
enum source_state
|
||||
{
|
||||
SOURCE_STATE_STOPPED = 0,
|
||||
|
@ -96,8 +90,16 @@ struct media_source
|
|||
{
|
||||
struct list entry;
|
||||
IMFMediaSource *source;
|
||||
IMFPresentationDescriptor *pd;
|
||||
enum source_state state;
|
||||
struct list streams;
|
||||
};
|
||||
|
||||
struct source_node
|
||||
{
|
||||
struct list entry;
|
||||
IMFMediaStream *stream;
|
||||
IMFMediaSource *source;
|
||||
DWORD stream_id;
|
||||
};
|
||||
|
||||
struct media_sink
|
||||
|
@ -125,6 +127,7 @@ struct media_session
|
|||
IMFTopology *current_topology;
|
||||
MF_TOPOSTATUS topo_status;
|
||||
struct list sources;
|
||||
struct list source_nodes;
|
||||
struct list sinks;
|
||||
} presentation;
|
||||
struct list topologies;
|
||||
|
@ -536,8 +539,8 @@ static HRESULT session_bind_output_nodes(IMFTopology *topology)
|
|||
|
||||
static void session_clear_presentation(struct media_session *session)
|
||||
{
|
||||
struct source_node *src_node, *src_node2;
|
||||
struct media_source *source, *source2;
|
||||
struct media_stream *stream, *stream2;
|
||||
struct media_sink *sink, *sink2;
|
||||
|
||||
IMFTopology_Clear(session->presentation.current_topology);
|
||||
|
@ -546,20 +549,22 @@ static void session_clear_presentation(struct media_session *session)
|
|||
LIST_FOR_EACH_ENTRY_SAFE(source, source2, &session->presentation.sources, struct media_source, entry)
|
||||
{
|
||||
list_remove(&source->entry);
|
||||
|
||||
LIST_FOR_EACH_ENTRY_SAFE(stream, stream2, &source->streams, struct media_stream, entry)
|
||||
{
|
||||
list_remove(&stream->entry);
|
||||
if (stream->stream)
|
||||
IMFMediaStream_Release(stream->stream);
|
||||
heap_free(stream);
|
||||
}
|
||||
|
||||
if (source->source)
|
||||
IMFMediaSource_Release(source->source);
|
||||
if (source->pd)
|
||||
IMFPresentationDescriptor_Release(source->pd);
|
||||
heap_free(source);
|
||||
}
|
||||
|
||||
LIST_FOR_EACH_ENTRY_SAFE(src_node, src_node2, &session->presentation.source_nodes, struct source_node, entry)
|
||||
{
|
||||
list_remove(&src_node->entry);
|
||||
if (src_node->stream)
|
||||
IMFMediaStream_Release(src_node->stream);
|
||||
heap_free(src_node);
|
||||
}
|
||||
|
||||
|
||||
LIST_FOR_EACH_ENTRY_SAFE(sink, sink2, &session->presentation.sinks, struct media_sink, entry)
|
||||
{
|
||||
list_remove(&sink->entry);
|
||||
|
@ -648,6 +653,130 @@ static void session_start(struct media_session *session, const GUID *time_format
|
|||
LeaveCriticalSection(&session->cs);
|
||||
}
|
||||
|
||||
static struct media_source *session_get_media_source(struct media_session *session, IMFMediaSource *source)
|
||||
{
|
||||
struct media_source *cur;
|
||||
|
||||
LIST_FOR_EACH_ENTRY(cur, &session->presentation.sources, struct media_source, entry)
|
||||
{
|
||||
if (source == cur->source)
|
||||
return cur;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void session_release_media_source(struct media_source *source)
|
||||
{
|
||||
IMFMediaSource_Release(source->source);
|
||||
if (source->pd)
|
||||
IMFPresentationDescriptor_Release(source->pd);
|
||||
heap_free(source);
|
||||
}
|
||||
|
||||
static HRESULT session_add_media_source(struct media_session *session, IMFTopologyNode *node, IMFMediaSource *source)
|
||||
{
|
||||
struct media_source *media_source;
|
||||
HRESULT hr;
|
||||
|
||||
if (session_get_media_source(session, source))
|
||||
return S_FALSE;
|
||||
|
||||
if (!(media_source = heap_alloc_zero(sizeof(*media_source))))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
media_source->source = source;
|
||||
IMFMediaSource_AddRef(media_source->source);
|
||||
|
||||
hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, &IID_IMFPresentationDescriptor,
|
||||
(void **)&media_source->pd);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
list_add_tail(&session->presentation.sources, &media_source->entry);
|
||||
else
|
||||
session_release_media_source(media_source);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT session_add_source_node(struct media_session *session, IMFTopologyNode *node, IMFMediaSource *source)
|
||||
{
|
||||
struct source_node *source_node;
|
||||
IMFStreamDescriptor *sd;
|
||||
DWORD stream_id;
|
||||
HRESULT hr;
|
||||
|
||||
if (FAILED(hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR, &IID_IMFStreamDescriptor,
|
||||
(void **)&sd)))
|
||||
{
|
||||
WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#x.\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &stream_id);
|
||||
IMFStreamDescriptor_Release(sd);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
if (!(source_node = heap_alloc_zero(sizeof(*source_node))))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
source_node->source = source;
|
||||
IMFMediaSource_AddRef(source_node->source);
|
||||
|
||||
list_add_tail(&session->presentation.source_nodes, &source_node->entry);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static void session_collect_source_nodes(struct media_session *session)
|
||||
{
|
||||
IMFTopology *topology;
|
||||
IMFTopologyNode *node;
|
||||
IMFCollection *nodes;
|
||||
DWORD count, i;
|
||||
HRESULT hr;
|
||||
|
||||
if (!list_empty(&session->presentation.source_nodes))
|
||||
return;
|
||||
|
||||
topology = session->presentation.current_topology;
|
||||
|
||||
if (!topology || FAILED(IMFTopology_GetSourceNodeCollection(topology, &nodes)))
|
||||
return;
|
||||
|
||||
if (FAILED(IMFCollection_GetElementCount(nodes, &count)))
|
||||
return;
|
||||
|
||||
/* Create list of distinct sources, and whole list of source nodes. */
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
if (SUCCEEDED(hr = IMFCollection_GetElement(nodes, i, (IUnknown **)&node)))
|
||||
{
|
||||
IMFMediaSource *source;
|
||||
|
||||
if (FAILED(IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_SOURCE, &IID_IMFMediaSource, (void **)&source)))
|
||||
{
|
||||
WARN("Missing MF_TOPONODE_SOURCE, hr %#x.\n", hr);
|
||||
IMFTopologyNode_Release(node);
|
||||
continue;
|
||||
}
|
||||
|
||||
hr = session_add_media_source(session, node, source);
|
||||
IMFMediaSource_Release(source);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (FAILED(hr = session_add_source_node(session, node, source)))
|
||||
WARN("Failed to add source node, hr %#x.\n", hr);
|
||||
}
|
||||
|
||||
IMFMediaSource_Release(source);
|
||||
IMFTopologyNode_Release(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void session_raise_topology_set(struct media_session *session, IMFTopology *topology, HRESULT status)
|
||||
{
|
||||
PROPVARIANT param;
|
||||
|
@ -669,6 +798,8 @@ static void session_set_current_topology(struct media_session *session, IMFTopol
|
|||
return;
|
||||
}
|
||||
|
||||
session_collect_source_nodes(session);
|
||||
|
||||
/* FIXME: attributes are all zero for now */
|
||||
if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime, &GUID_NULL, S_OK, NULL, &event)))
|
||||
{
|
||||
|
@ -1220,17 +1351,36 @@ static HRESULT WINAPI session_events_callback_GetParameters(IMFAsyncCallback *if
|
|||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT session_add_media_stream(struct media_source *source, IMFMediaStream *stream)
|
||||
static HRESULT session_add_media_stream(struct media_session *session, IMFMediaSource *source, IMFMediaStream *stream)
|
||||
{
|
||||
struct media_stream *media_stream;
|
||||
struct source_node *node;
|
||||
IMFStreamDescriptor *sd;
|
||||
DWORD stream_id = 0;
|
||||
HRESULT hr;
|
||||
|
||||
if (!(media_stream = heap_alloc_zero(sizeof(*media_stream))))
|
||||
return E_OUTOFMEMORY;
|
||||
if (FAILED(hr = IMFMediaStream_GetStreamDescriptor(stream, &sd)))
|
||||
return hr;
|
||||
|
||||
media_stream->stream = stream;
|
||||
IMFMediaStream_AddRef(media_stream->stream);
|
||||
hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &stream_id);
|
||||
IMFStreamDescriptor_Release(sd);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
list_add_tail(&source->streams, &media_stream->entry);
|
||||
LIST_FOR_EACH_ENTRY(node, &session->presentation.source_nodes, struct source_node, entry)
|
||||
{
|
||||
if (node->source == source && node->stream_id == stream_id)
|
||||
{
|
||||
if (node->stream)
|
||||
{
|
||||
WARN("Source node already has stream set.\n");
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
node->stream = stream;
|
||||
IMFMediaStream_AddRef(node->stream);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -1322,7 +1472,6 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM
|
|||
enum source_state source_state;
|
||||
IMFMediaEvent *event = NULL;
|
||||
MediaEventType event_type;
|
||||
struct media_source *cur;
|
||||
IMFMediaSource *source;
|
||||
IMFMediaStream *stream;
|
||||
PROPVARIANT value;
|
||||
|
@ -1394,22 +1543,12 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM
|
|||
break;
|
||||
|
||||
EnterCriticalSection(&session->cs);
|
||||
|
||||
LIST_FOR_EACH_ENTRY(cur, &session->presentation.sources, struct media_source, entry)
|
||||
{
|
||||
if (source == cur->source)
|
||||
{
|
||||
hr = session_add_media_stream(cur, stream);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
if (SUCCEEDED(hr = session_add_media_stream(session, source, stream)))
|
||||
hr = IMFMediaStream_BeginGetEvent(stream, &session->events_callback, (IUnknown *)stream);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&session->cs);
|
||||
|
||||
IMFMediaSource_Release(source);
|
||||
|
||||
break;
|
||||
default:
|
||||
;
|
||||
|
@ -1610,6 +1749,7 @@ HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **ses
|
|||
object->refcount = 1;
|
||||
list_init(&object->topologies);
|
||||
list_init(&object->presentation.sources);
|
||||
list_init(&object->presentation.source_nodes);
|
||||
list_init(&object->presentation.sinks);
|
||||
InitializeCriticalSection(&object->cs);
|
||||
|
||||
|
|
Loading…
Reference in New Issue