Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
February 2020
- 80 participants
- 2095 messages
[PATCH 08/14] mf: Query for optional event generator for sinks.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mf/session.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index 288ea60e6f..0bbf0bac56 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -107,6 +107,7 @@ struct media_sink
{
struct list entry;
IMFMediaSink *sink;
+ IMFMediaEventGenerator *event_generator;
};
struct output_node
@@ -573,13 +574,14 @@ static void session_clear_presentation(struct media_session *session)
heap_free(src_node);
}
-
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);
+ if (sink->event_generator)
+ IMFMediaEventGenerator_Release(sink->event_generator);
heap_free(sink);
}
}
@@ -812,6 +814,8 @@ static HRESULT session_add_media_sink(struct media_session *session, IMFTopology
media_sink->sink = sink;
IMFMediaSink_AddRef(media_sink->sink);
+ IMFMediaSink_QueryInterface(media_sink->sink, &IID_IMFMediaEventGenerator, (void **)&media_sink->event_generator);
+
list_add_tail(&session->presentation.sinks, &media_sink->entry);
return S_OK;
--
2.25.0
Feb. 28, 2020
[PATCH 07/14] mf: Keep a list of output streams.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mf/session.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 93 insertions(+)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index 12685583e2..288ea60e6f 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -109,6 +109,13 @@ struct media_sink
IMFMediaSink *sink;
};
+struct output_node
+{
+ struct list entry;
+ IMFStreamSink *stream;
+ enum object_state state;
+};
+
struct media_session
{
IMFMediaSession IMFMediaSession_iface;
@@ -130,6 +137,7 @@ struct media_session
struct list sources;
struct list source_nodes;
struct list sinks;
+ struct list output_nodes;
} presentation;
struct list topologies;
enum session_state state;
@@ -788,6 +796,89 @@ static void session_raise_topology_set(struct media_session *session, IMFTopolog
IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologySet, &GUID_NULL, status, ¶m);
}
+static HRESULT session_add_media_sink(struct media_session *session, IMFTopologyNode *node, IMFMediaSink *sink)
+{
+ struct media_sink *media_sink;
+
+ LIST_FOR_EACH_ENTRY(media_sink, &session->presentation.sinks, struct media_sink, entry)
+ {
+ if (sink == media_sink->sink)
+ return S_FALSE;
+ }
+
+ if (!(media_sink = heap_alloc_zero(sizeof(*media_sink))))
+ return E_OUTOFMEMORY;
+
+ media_sink->sink = sink;
+ IMFMediaSink_AddRef(media_sink->sink);
+
+ list_add_tail(&session->presentation.sinks, &media_sink->entry);
+
+ return S_OK;
+}
+
+static HRESULT session_collect_output_nodes(struct media_session *session)
+{
+ IMFTopology *topology = session->presentation.current_topology;
+ IMFTopologyNode *topo_node;
+ struct output_node *node;
+ IMFCollection *nodes;
+ DWORD count, i;
+ HRESULT hr;
+
+ if (!list_empty(&session->presentation.output_nodes))
+ 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)
+ {
+ IMFMediaSink *media_sink = NULL;
+
+ if (FAILED(hr = IMFCollection_GetElement(nodes, i, (IUnknown **)&topo_node)))
+ break;
+
+ if (!(node = heap_alloc_zero(sizeof(*node))))
+ hr = E_OUTOFMEMORY;
+
+ if (SUCCEEDED(hr))
+ hr = IMFTopologyNode_GetObject(topo_node, (IUnknown **)&node->stream);
+
+ if (SUCCEEDED(hr))
+ hr = IMFStreamSink_GetMediaSink(node->stream, &media_sink);
+
+ if (SUCCEEDED(hr))
+ hr = session_add_media_sink(session, topo_node, media_sink);
+
+ if (media_sink)
+ IMFMediaSink_Release(media_sink);
+
+ if (SUCCEEDED(hr))
+ {
+ list_add_tail(&session->presentation.output_nodes, &node->entry);
+ }
+ else if (node)
+ {
+ if (node->stream)
+ IMFStreamSink_Release(node->stream);
+ heap_free(node);
+ }
+
+ IMFTopologyNode_Release(topo_node);
+ }
+
+ IMFCollection_Release(nodes);
+
+ return hr;
+}
+
static void session_set_current_topology(struct media_session *session, IMFTopology *topology)
{
IMFMediaEvent *event;
@@ -800,6 +891,7 @@ static void session_set_current_topology(struct media_session *session, IMFTopol
}
session_collect_source_nodes(session);
+ session_collect_output_nodes(session);
/* FIXME: attributes are all zero for now */
if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime, &GUID_NULL, S_OK, NULL, &event)))
@@ -1752,6 +1844,7 @@ HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **ses
list_init(&object->presentation.sources);
list_init(&object->presentation.source_nodes);
list_init(&object->presentation.sinks);
+ list_init(&object->presentation.output_nodes);
InitializeCriticalSection(&object->cs);
if (FAILED(hr = MFCreateTopology(&object->presentation.current_topology)))
--
2.25.0
Feb. 28, 2020
[PATCH 06/14] mf: Use generic enum for object states.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mf/session.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index 17bb44eaa7..12685583e2 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -79,11 +79,12 @@ enum session_state
SESSION_STATE_SHUT_DOWN,
};
-enum source_state
+enum object_state
{
- SOURCE_STATE_STOPPED = 0,
- SOURCE_STATE_STARTED,
- SOURCE_STATE_PAUSED,
+ OBJ_STATE_STOPPED = 0,
+ OBJ_STATE_STARTED,
+ OBJ_STATE_PAUSED,
+ OBJ_STATE_INVALID,
};
struct media_source
@@ -91,7 +92,7 @@ struct media_source
struct list entry;
IMFMediaSource *source;
IMFPresentationDescriptor *pd;
- enum source_state state;
+ enum object_state state;
};
struct source_node
@@ -1385,7 +1386,7 @@ static HRESULT session_add_media_stream(struct media_session *session, IMFMediaS
return S_OK;
}
-static BOOL session_set_source_state(struct media_session *session, IMFMediaSource *source, enum source_state state)
+static BOOL session_set_source_state(struct media_session *session, IMFMediaSource *source, enum object_state state)
{
struct media_source *cur;
BOOL ret = TRUE;
@@ -1469,7 +1470,7 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM
{
struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
IMFMediaEventGenerator *event_source;
- enum source_state source_state;
+ enum object_state source_state;
IMFMediaEvent *event = NULL;
MediaEventType event_type;
IMFMediaSource *source;
@@ -1506,11 +1507,11 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM
case MESourcePaused:
case MESourceStopped:
if (event_type == MESourceStarted)
- source_state = SOURCE_STATE_STARTED;
+ source_state = OBJ_STATE_STARTED;
else if (event_type == MESourcePaused)
- source_state = SOURCE_STATE_PAUSED;
+ source_state = OBJ_STATE_PAUSED;
else
- source_state = SOURCE_STATE_STOPPED;
+ source_state = OBJ_STATE_STOPPED;
EnterCriticalSection(&session->cs);
--
2.25.0
Feb. 28, 2020
[PATCH 05/14] mf: Use separate list for source streams.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mf/session.c | 218 +++++++++++++++++++++++++++++++++++++---------
1 file changed, 179 insertions(+), 39 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index 0963bcb06e..17bb44eaa7 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -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);
--
2.25.0
Feb. 28, 2020
[PATCH 04/14] mf: Create separate topology object and use it as current.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mf/session.c | 243 ++++++++++++++++++++++++----------------------
1 file changed, 125 insertions(+), 118 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index 6da495e3c1..0963bcb06e 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -122,7 +122,8 @@ struct media_session
IMFQualityManager *quality_manager;
struct
{
- struct queued_topology current_topology;
+ IMFTopology *current_topology;
+ MF_TOPOSTATUS topo_status;
struct list sources;
struct list sinks;
} presentation;
@@ -446,7 +447,7 @@ static void session_clear_topologies(struct media_session *session)
}
}
-static void session_set_topo_status(struct media_session *session, struct queued_topology *topology, HRESULT status,
+static void session_set_topo_status(struct media_session *session, HRESULT status,
MF_TOPOSTATUS topo_status)
{
IMFMediaEvent *event;
@@ -455,20 +456,20 @@ static void session_set_topo_status(struct media_session *session, struct queued
if (topo_status == MF_TOPOSTATUS_INVALID)
return;
- if (topo_status > topology->status)
+ if (topo_status > session->presentation.topo_status)
{
- param.vt = topology ? VT_UNKNOWN : VT_EMPTY;
- param.punkVal = topology ? (IUnknown *)topology->topology : NULL;
+ param.vt = VT_UNKNOWN;
+ param.punkVal = (IUnknown *)session->presentation.current_topology;
if (FAILED(MFCreateMediaEvent(MESessionTopologyStatus, &GUID_NULL, status, ¶m, &event)))
return;
+ session->presentation.topo_status = topo_status;
+
IMFMediaEvent_SetUINT32(event, &MF_EVENT_TOPOLOGY_STATUS, topo_status);
- topology->status = topo_status;
IMFMediaEventQueue_QueueEvent(session->event_queue, event);
+ IMFMediaEvent_Release(event);
}
-
- IMFMediaEvent_Release(event);
}
static HRESULT session_bind_output_nodes(IMFTopology *topology)
@@ -533,36 +534,14 @@ static HRESULT session_bind_output_nodes(IMFTopology *topology)
return hr;
}
-static IMFTopology *session_get_next_topology(struct media_session *session)
-{
- struct queued_topology *queued;
-
- if (!session->presentation.current_topology.topology)
- {
- struct list *head = list_head(&session->topologies);
- if (!head)
- return NULL;
-
- queued = LIST_ENTRY(head, struct queued_topology, entry);
- session->presentation.current_topology = *queued;
- list_remove(&queued->entry);
- heap_free(queued);
- }
-
- return session->presentation.current_topology.topology;
-}
-
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)
- {
- IMFTopology_Release(session->presentation.current_topology.topology);
- session->presentation.current_topology.topology = NULL;
- }
+ IMFTopology_Clear(session->presentation.current_topology);
+ session->presentation.topo_status = MF_TOPOSTATUS_INVALID;
LIST_FOR_EACH_ENTRY_SAFE(source, source2, &session->presentation.sources, struct media_source, entry)
{
@@ -594,7 +573,6 @@ static void session_clear_presentation(struct media_session *session)
static void session_start(struct media_session *session, const GUID *time_format, const PROPVARIANT *start_position)
{
IMFTopologyNode *node;
- IMFTopology *topology;
IMFCollection *nodes;
DWORD count, i;
HRESULT hr;
@@ -604,9 +582,8 @@ static void session_start(struct media_session *session, const GUID *time_format
switch (session->state)
{
case SESSION_STATE_STOPPED:
- topology = session_get_next_topology(session);
- if (!topology || FAILED(IMFTopology_GetSourceNodeCollection(topology, &nodes)))
+ if (FAILED(IMFTopology_GetSourceNodeCollection(session->presentation.current_topology, &nodes)))
break;
if (FAILED(IMFCollection_GetElementCount(nodes, &count)))
@@ -671,6 +648,111 @@ static void session_start(struct media_session *session, const GUID *time_format
LeaveCriticalSection(&session->cs);
}
+static void session_raise_topology_set(struct media_session *session, IMFTopology *topology, HRESULT status)
+{
+ PROPVARIANT param;
+
+ param.vt = topology ? VT_UNKNOWN : VT_EMPTY;
+ param.punkVal = (IUnknown *)topology;
+
+ IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologySet, &GUID_NULL, status, ¶m);
+}
+
+static void session_set_current_topology(struct media_session *session, IMFTopology *topology)
+{
+ IMFMediaEvent *event;
+ HRESULT hr;
+
+ if (FAILED(hr = IMFTopology_CloneFrom(session->presentation.current_topology, topology)))
+ {
+ WARN("Failed to clone topology, hr %#x.\n", hr);
+ return;
+ }
+
+ /* FIXME: attributes are all zero for now */
+ if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime, &GUID_NULL, S_OK, NULL, &event)))
+ {
+ IMFMediaEvent_SetUINT64(event, &MF_EVENT_START_PRESENTATION_TIME, 0);
+ IMFMediaEvent_SetUINT64(event, &MF_EVENT_PRESENTATION_TIME_OFFSET, 0);
+ IMFMediaEvent_GetUINT64(event, &MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT, 0);
+
+ IMFMediaEventQueue_QueueEvent(session->event_queue, event);
+ IMFMediaEvent_Release(event);
+ }
+}
+
+static void session_set_topology(struct media_session *session, DWORD flags, IMFTopology *topology)
+{
+ HRESULT status = S_OK;
+
+ /* Resolve unless claimed to be full. */
+ if (!(flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT) && topology)
+ {
+ 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;
+ }
+ }
+ }
+
+ EnterCriticalSection(&session->cs);
+
+ if (flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT)
+ {
+ if ((topology && topology == session->presentation.current_topology) || !topology)
+ {
+ /* FIXME: stop current topology, queue next one. */
+ session_clear_presentation(session);
+ }
+ else
+ status = S_FALSE;
+
+ topology = NULL;
+ }
+ else if (topology && flags & MFSESSION_SETTOPOLOGY_IMMEDIATE)
+ {
+ session_clear_topologies(session);
+ session_clear_presentation(session);
+ }
+
+ session_raise_topology_set(session, topology, status);
+
+ /* With no current topology set it right away, otherwise queue. */
+ if (topology)
+ {
+ if (session->presentation.topo_status == MF_TOPOSTATUS_INVALID)
+ {
+ session_set_current_topology(session, topology);
+ }
+ else
+ {
+ struct queued_topology *queued_topology;
+
+ if ((queued_topology = heap_alloc_zero(sizeof(*queued_topology))))
+ {
+ queued_topology->topology = topology;
+ IMFTopology_AddRef(queued_topology->topology);
+
+ list_add_tail(&session->topologies, &queued_topology->entry);
+ }
+ }
+ }
+
+ if (status == S_OK)
+ session_set_topo_status(session, S_OK, MF_TOPOSTATUS_READY);
+
+ LeaveCriticalSection(&session->cs);
+}
+
static HRESULT WINAPI mfsession_QueryInterface(IMFMediaSession *iface, REFIID riid, void **out)
{
struct media_session *session = impl_from_IMFMediaSession(iface);
@@ -718,6 +800,8 @@ static ULONG WINAPI mfsession_Release(IMFMediaSession *iface)
{
session_clear_topologies(session);
session_clear_presentation(session);
+ if (session->presentation.current_topology)
+ IMFTopology_Release(session->presentation.current_topology);
if (session->event_queue)
IMFMediaEventQueue_Release(session->event_queue);
if (session->clock)
@@ -1053,21 +1137,10 @@ static HRESULT WINAPI session_commands_callback_GetParameters(IMFAsyncCallback *
return E_NOTIMPL;
}
-static void session_raise_topology_set(struct media_session *session, IMFTopology *topology, HRESULT status)
-{
- PROPVARIANT param;
-
- param.vt = topology ? VT_UNKNOWN : VT_EMPTY;
- param.punkVal = (IUnknown *)topology;
-
- IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologySet, &GUID_NULL, status, ¶m);
-}
-
static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
{
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)
{
@@ -1080,76 +1153,8 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface,
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 = NULL;
- DWORD flags = op->u.set_topology.flags;
-
- /* Resolve unless claimed to be full. */
- if (!(flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT) && topology)
- {
- 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;
- topo_status = MF_TOPOSTATUS_READY;
- }
- }
-
- if (SUCCEEDED(status))
- {
- if (!(queued_topology = heap_alloc_zero(sizeof(*queued_topology))))
- status = E_OUTOFMEMORY;
- }
-
- if (SUCCEEDED(status))
- {
- queued_topology->topology = topology;
- IMFTopology_AddRef(queued_topology->topology);
- }
- }
-
- EnterCriticalSection(&session->cs);
-
- if (flags & MFSESSION_SETTOPOLOGY_CLEAR_CURRENT)
- {
- if ((topology && topology == session->presentation.current_topology.topology) || !topology)
- {
- /* FIXME: stop current topology, queue next one. */
- session_clear_presentation(session);
- }
- else
- status = S_FALSE;
- topo_status = MF_TOPOSTATUS_READY;
- queued_topology = &session->presentation.current_topology;
- }
- else if (queued_topology)
- {
- if (flags & MFSESSION_SETTOPOLOGY_IMMEDIATE)
- {
- session_clear_topologies(session);
- session_clear_presentation(session);
- }
-
- list_add_tail(&session->topologies, &queued_topology->entry);
- }
-
- session_raise_topology_set(session, topology, status);
- session_set_topo_status(session, queued_topology, status, topo_status);
-
- LeaveCriticalSection(&session->cs);
-
+ session_set_topology(session, op->u.set_topology.flags, op->u.set_topology.topology);
break;
- }
case SESSION_CMD_START:
{
session_start(session, &op->u.start.time_format, &op->u.start.start_position);
@@ -1247,7 +1252,7 @@ static BOOL session_set_source_state(struct media_session *session, IMFMediaSour
static HRESULT session_set_sinks_clock(struct media_session *session)
{
- IMFTopology *topology = session->presentation.current_topology.topology;
+ IMFTopology *topology = session->presentation.current_topology;
IMFTopologyNode *node;
IMFCollection *nodes;
DWORD count, i;
@@ -1363,8 +1368,7 @@ 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);
+ session_set_topo_status(session, S_OK, MF_TOPOSTATUS_STARTED_SOURCE);
if (session->state == SESSION_STATE_STARTING)
{
@@ -1609,6 +1613,9 @@ HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **ses
list_init(&object->presentation.sinks);
InitializeCriticalSection(&object->cs);
+ if (FAILED(hr = MFCreateTopology(&object->presentation.current_topology)))
+ goto failed;
+
if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
goto failed;
--
2.25.0
Feb. 28, 2020
[PATCH 03/14] mf: Subscribe for next pipeline object event after processing current one.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mf/session.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index 2ef4b01028..6da495e3c1 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -1416,6 +1416,10 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM
failed:
if (event)
IMFMediaEvent_Release(event);
+
+ if (FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(event_source, iface, (IUnknown *)event_source)))
+ WARN("Failed to re-subscribe, hr %#x.\n", hr);
+
IMFMediaEventGenerator_Release(event_source);
return hr;
--
2.25.0
Feb. 28, 2020
[PATCH 02/14] mf: Add support for returning slowest/fastest rates for session.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mf/session.c | 62 ++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 58 insertions(+), 4 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index 5ee4074379..2ef4b01028 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -17,6 +17,7 @@
*/
#include <stdarg.h>
+#include <math.h>
#define COBJMACROS
@@ -1447,20 +1448,73 @@ static ULONG WINAPI session_rate_support_Release(IMFRateSupport *iface)
return IMFMediaSession_Release(&session->IMFMediaSession_iface);
}
+static void session_presentation_object_get_rate(IUnknown *object, MFRATE_DIRECTION direction,
+ BOOL thin, BOOL fastest, float *result)
+{
+ IMFRateSupport *rate_support;
+ float rate;
+
+ if (SUCCEEDED(MFGetService(object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support)))
+ {
+ rate = 0.0f;
+ if (fastest)
+ {
+ if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support, direction, thin, &rate)))
+ *result = min(fabsf(rate), *result);
+ }
+ else
+ {
+ if (SUCCEEDED(IMFRateSupport_GetSlowestRate(rate_support, direction, thin, &rate)))
+ *result = max(fabsf(rate), *result);
+ }
+
+ IMFRateSupport_Release(rate_support);
+ }
+}
+
+static HRESULT session_get_presentation_rate(struct media_session *session, MFRATE_DIRECTION direction,
+ BOOL thin, BOOL fastest, float *result)
+{
+ struct media_source *source;
+ struct media_sink *sink;
+
+ *result = 0.0f;
+
+ EnterCriticalSection(&session->cs);
+
+ LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
+ {
+ session_presentation_object_get_rate((IUnknown *)source->source, direction, thin, fastest, result);
+ }
+
+ LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
+ {
+ session_presentation_object_get_rate((IUnknown *)sink->sink, direction, thin, fastest, result);
+ }
+
+ LeaveCriticalSection(&session->cs);
+
+ return S_OK;
+}
+
static HRESULT WINAPI session_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
BOOL thin, float *rate)
{
- FIXME("%p, %d, %d, %p.\n", iface, direction, thin, rate);
+ struct media_session *session = impl_session_from_IMFRateSupport(iface);
- return E_NOTIMPL;
+ TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
+
+ return session_get_presentation_rate(session, direction, thin, FALSE, rate);
}
static HRESULT WINAPI session_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
BOOL thin, float *rate)
{
- FIXME("%p, %d, %d, %p.\n", iface, direction, thin, rate);
+ struct media_session *session = impl_session_from_IMFRateSupport(iface);
- return E_NOTIMPL;
+ TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
+
+ return session_get_presentation_rate(session, direction, thin, TRUE, rate);
}
static HRESULT WINAPI session_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
--
2.25.0
Feb. 28, 2020
[PATCH 01/14] include: Add more Media Foundation error codes.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
include/mferror.h | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/include/mferror.h b/include/mferror.h
index 6341d832ab..523800d7f0 100644
--- a/include/mferror.h
+++ b/include/mferror.h
@@ -166,4 +166,46 @@
#define MF_E_CLOCK_NOT_SIMPLE _HRESULT_TYPEDEF_(0xc00d9c43)
#define MF_S_CLOCK_STOPPED _HRESULT_TYPEDEF_(0x000d9c44)
+#define MF_E_NO_MORE_DROP_MODES _HRESULT_TYPEDEF_(0xc00da028)
+#define MF_E_NO_MORE_QUALITY_LEVELS _HRESULT_TYPEDEF_(0xc00da029)
+#define MF_E_DROPTIME_NOT_SUPPORTED _HRESULT_TYPEDEF_(0xc00da02a)
+#define MF_E_QUALITYKNOB_WAIT_LONGER _HRESULT_TYPEDEF_(0xc00da02b)
+#define MF_E_QM_INVALIDSTATE _HRESULT_TYPEDEF_(0xc00da02c)
+
+#define MF_E_TRANSCODE_NO_CONTAINERTYPE _HRESULT_TYPEDEF_(0xc00da410)
+#define MF_E_TRANSCODE_PROFILE_NO_MATCHING_STREAMS _HRESULT_TYPEDEF_(0xc00da411)
+#define MF_E_TRANSCODE_NO_MATCHING_ENCODER _HRESULT_TYPEDEF_(0xc00da412)
+#define MF_E_TRANSCODE_INVALID_PROFILE _HRESULT_TYPEDEF_(0xc00da413)
+
+#define MF_E_ALLOCATOR_NOT_INITIALIZED _HRESULT_TYPEDEF_(0xc00da7f8)
+#define MF_E_ALLOCATOR_NOT_COMMITED _HRESULT_TYPEDEF_(0xc00da7f9)
+#define MF_E_ALLOCATOR_ALREADY_COMMITED _HRESULT_TYPEDEF_(0xc00da7fa)
+#define MF_E_STREAM_ERROR _HRESULT_TYPEDEF_(0xc00da7fb)
+#define MF_E_INVALID_STREAM_STATE _HRESULT_TYPEDEF_(0xc00da7fc)
+#define MF_E_HW_STREAM_NOT_CONNECTED _HRESULT_TYPEDEF_(0xc00da7fd)
+
+#define MF_E_NO_CAPTURE_DEVICES_AVAILABLE _HRESULT_TYPEDEF_(0xc00dabe0)
+#define MF_E_CAPTURE_SINK_OUTPUT_NOT_SET _HRESULT_TYPEDEF_(0xc00dabe1)
+#define MF_E_CAPTURE_SINK_MIRROR_ERROR _HRESULT_TYPEDEF_(0xc00dabe2)
+#define MF_E_CAPTURE_SINK_ROTATE_ERROR _HRESULT_TYPEDEF_(0xc00dabe3)
+#define MF_E_CAPTURE_ENGINE_INVALID_OP _HRESULT_TYPEDEF_(0xc00dabe4)
+#define MF_E_CAPTURE_ENGINE_ALL_EFFECTS_REMOVED _HRESULT_TYPEDEF_(0xc00dabe5)
+#define MF_E_CAPTURE_SOURCE_NO_INDEPENDENT_PHOTO_STREAM_PRESENT _HRESULT_TYPEDEF_(0xc00dabe6)
+#define MF_E_CAPTURE_SOURCE_NO_VIDEO_STREAM_PRESENT _HRESULT_TYPEDEF_(0xc00dabe7)
+#define MF_E_CAPTURE_SOURCE_NO_AUDIO_STREAM_PRESENT _HRESULT_TYPEDEF_(0xc00dabe8)
+#define MF_E_CAPTURE_SOURCE_DEVICE_EXTENDEDPROP_OP_IN_PROGRESS _HRESULT_TYPEDEF_(0xc00dabe9)
+#define MF_E_CAPTURE_PROPERTY_SET_DURING_PHOTO _HRESULT_TYPEDEF_(0xc00dabea)
+#define MF_E_CAPTURE_NO_SAMPLES_IN_QUEUE _HRESULT_TYPEDEF_(0xc00dabeb)
+#define MF_E_HW_ACCELERATED_THUMBNAIL_NOT_SUPPORTED _HRESULT_TYPEDEF_(0xc00dabec)
+#define MF_E_UNSUPPORTED_CAPTURE_DEVICE_PRESENT _HRESULT_TYPEDEF_(0xc00dabed)
+
+#define MF_E_TIMELINECONTROLLER_UNSUPPORTED_SOURCE_TYPE _HRESULT_TYPEDEF_(0xc00dafc8)
+#define MF_E_TIMELINECONTROLLER_NOT_ALLOWED _HRESULT_TYPEDEF_(0xc00dafc9)
+#define MF_E_TIMELINECONTROLLER_CANNOT_ATTACH _HRESULT_TYPEDEF_(0xc00dafca)
+
+#define MF_E_MEDIA_EXTENSION_APPSERVICE_CONNECTION_FAILED _HRESULT_TYPEDEF_(0xc00db3b0)
+#define MF_E_MEDIA_EXTENSION_APPSERVICE_REQUEST_FAILED _HRESULT_TYPEDEF_(0xc00db3b1)
+#define MF_E_MEDIA_EXTENSION_PACKAGE_INTEGRITY_CHECK_FAILED _HRESULT_TYPEDEF_(0xc00db3b2)
+#define MF_E_MEDIA_EXTENSION_PACKAGE_LICENSE_INVALID _HRESULT_TYPEDEF_(0xc00db3b3)
+
#endif /* __WINE_MFERROR_H */
--
2.25.0
Feb. 28, 2020
Re: [PATCH 1/2] ntdll/tests: Create a test for RtlGetNtProductType().
by Serge Gautherie
See https://testbot.winehq.org/JobDetails.pl?Key=65973 :
w1064v1709 and w1064v1809 do crash on 32 bit (only).
Yet, I believe my test is correct, as far as I know.
--
Feb. 28, 2020
Re: [PATCH 1/2] ntdll/tests: Create a test for RtlGetNtProductType().
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=65974
Your paranoid android.
=== w1064v1809 (32 bit report) ===
ntdll:
0670:rtl: unhandled exception c0000005 at 77D89D4B
=== w1064v1809_2scr (32 bit report) ===
ntdll:
1a04:rtl: unhandled exception c0000005 at 77BA9D4B
=== w1064v1809_ar (32 bit report) ===
ntdll:
1854:rtl: unhandled exception c0000005 at 77219D4B
=== w1064v1809_he (32 bit report) ===
ntdll:
194c:rtl: unhandled exception c0000005 at 77D39D4B
=== w1064v1809_ja (32 bit report) ===
ntdll:
1968:rtl: unhandled exception c0000005 at 772B9D4B
=== w1064v1809_zh_CN (32 bit report) ===
ntdll:
18bc:rtl: unhandled exception c0000005 at 77979D4B
Feb. 28, 2020