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:
Nikolay Sivov 2020-02-28 15:00:55 +03:00 committed by Alexandre Julliard
parent a93dde5ad8
commit adb420ee0d
1 changed files with 179 additions and 39 deletions

View File

@ -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))
hr = IMFMediaStream_BeginGetEvent(stream, &session->events_callback, (IUnknown *)stream);
break;
}
}
if (SUCCEEDED(hr = session_add_media_stream(session, source, stream)))
hr = IMFMediaStream_BeginGetEvent(stream, &session->events_callback, (IUnknown *)stream);
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);