mf: Set presentation clock for sinks, subscribe to sink events.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
stable
Nikolay Sivov 2019-10-04 14:42:48 +03:00 committed by Alexandre Julliard
parent 01bab1876d
commit 3bd1e1edf7
1 changed files with 93 additions and 0 deletions

View File

@ -99,6 +99,12 @@ struct media_source
struct list streams;
};
struct media_sink
{
struct list entry;
IMFMediaSink *sink;
};
struct media_session
{
IMFMediaSession IMFMediaSession_iface;
@ -117,6 +123,7 @@ struct media_session
{
struct queued_topology current_topology;
struct list sources;
struct list sinks;
} presentation;
struct list topologies;
enum session_state state;
@ -467,6 +474,7 @@ static void session_clear_presentation(struct media_session *session)
{
struct media_source *source, *source2;
struct media_stream *stream, *stream2;
struct media_sink *sink, *sink2;
if (session->presentation.current_topology.topology)
{
@ -490,6 +498,15 @@ static void session_clear_presentation(struct media_session *session)
IMFMediaSource_Release(source->source);
heap_free(source);
}
LIST_FOR_EACH_ENTRY_SAFE(sink, sink2, &session->presentation.sinks, struct media_sink, entry)
{
list_remove(&sink->entry);
if (sink->sink)
IMFMediaSink_Release(sink->sink);
heap_free(sink);
}
}
static void session_start(struct media_session *session, const GUID *time_format, const PROPVARIANT *start_position)
@ -1142,6 +1159,71 @@ static BOOL session_set_source_state(struct media_session *session, IMFMediaSour
return ret;
}
static HRESULT session_set_sinks_clock(struct media_session *session)
{
IMFTopology *topology = session->presentation.current_topology.topology;
IMFTopologyNode *node;
IMFCollection *nodes;
DWORD count, i;
HRESULT hr;
if (!list_empty(&session->presentation.sinks))
return S_OK;
if (FAILED(hr = IMFTopology_GetOutputNodeCollection(topology, &nodes)))
return hr;
if (FAILED(hr = IMFCollection_GetElementCount(nodes, &count)))
{
IMFCollection_Release(nodes);
return hr;
}
for (i = 0; i < count; ++i)
{
IMFStreamSink *stream_sink = NULL;
struct media_sink *sink;
if (FAILED(hr = IMFCollection_GetElement(nodes, i, (IUnknown **)&node)))
break;
if (!(sink = heap_alloc_zero(sizeof(*sink))))
hr = E_OUTOFMEMORY;
if (SUCCEEDED(hr))
hr = IMFTopologyNode_GetObject(node, (IUnknown **)&stream_sink);
if (SUCCEEDED(hr))
hr = IMFStreamSink_GetMediaSink(stream_sink, &sink->sink);
if (SUCCEEDED(hr))
hr = IMFMediaSink_SetPresentationClock(sink->sink, session->clock);
if (SUCCEEDED(hr))
hr = IMFStreamSink_BeginGetEvent(stream_sink, &session->events_callback, (IUnknown *)stream_sink);
if (stream_sink)
IMFStreamSink_Release(stream_sink);
if (SUCCEEDED(hr))
{
list_add_tail(&session->presentation.sinks, &sink->entry);
}
else if (sink)
{
if (sink->sink)
IMFMediaSink_Release(sink->sink);
heap_free(sink);
}
IMFTopologyNode_Release(node);
}
IMFCollection_Release(nodes);
return hr;
}
static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
{
struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
@ -1194,9 +1276,19 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM
ret = session_set_source_state(session, (IMFMediaSource *)event_source, source_state);
if (ret && event_type == MESourceStarted)
{
session_set_topo_status(session, &session->presentation.current_topology, S_OK,
MF_TOPOSTATUS_STARTED_SOURCE);
if (session->state == SESSION_STATE_STARTING)
{
if (SUCCEEDED(session_set_sinks_clock(session)))
{
session->state = SESSION_STATE_RUNNING;
}
}
}
LeaveCriticalSection(&session->cs);
break;
case MENewStream:
@ -1371,6 +1463,7 @@ HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **ses
object->refcount = 1;
list_init(&object->topologies);
list_init(&object->presentation.sources);
list_init(&object->presentation.sinks);
InitializeCriticalSection(&object->cs);
if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))