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 v2 3/3] makedep: Build builtin programs with ucrt.
by Jacek Caban
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
tools/makedep.c | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
Feb. 28, 2020
[PATCH v2 2/3] msvcrt: Silence wide environment inisialization debug messages.
by Jacek Caban
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/msvcrt/data.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
Feb. 28, 2020
[PATCH v2 1/3] ucrtbase: Add exe exntry points implementation.
by Jacek Caban
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/msvcrt/crt_main.c | 16 +++++++++++++++-
dlls/msvcrt/crt_wmain.c | 16 +++++++++++++++-
dlls/ucrtbase/Makefile.in | 5 +++++
3 files changed, 35 insertions(+), 2 deletions(-)
Feb. 28, 2020
Re: [PATCH 2/2] ntdll: RtlGetNtProductType() should not validate 'type' parameter.
by Gabriel Ivăncescu
Hi Serge,
On 28/02/2020 13:11, Serge Gautherie wrote:
> Signed-off-by: Serge Gautherie <winehq-git_serge_180711(a)gautherie.fr>
> ---
> dlls/ntdll/version.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/dlls/ntdll/version.c b/dlls/ntdll/version.c
> index 61e48f6..e03bc69 100644
> --- a/dlls/ntdll/version.c
> +++ b/dlls/ntdll/version.c
> @@ -637,7 +637,7 @@ void WINAPI RtlGetNtVersionNumbers( LPDWORD major, LPDWORD minor, LPDWORD build
> */
> BOOLEAN WINAPI RtlGetNtProductType( LPDWORD type )
> {
> - if (type) *type = current_version->wProductType;
> + *type = current_version->wProductType;
> return TRUE;
> }
>
>
Does some app depend on this?
Feb. 28, 2020
[PATCH 14/14] mf: Implement Stop() command for media session.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mf/session.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 71 insertions(+)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index 485b336570..76310040ee 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -79,6 +79,8 @@ enum session_state
SESSION_STATE_PAUSING_SINKS,
SESSION_STATE_PAUSING_SOURCES,
SESSION_STATE_PAUSED,
+ SESSION_STATE_STOPPING_SINKS,
+ SESSION_STATE_STOPPING_SOURCES,
SESSION_STATE_CLOSED,
SESSION_STATE_SHUT_DOWN,
};
@@ -676,6 +678,36 @@ static void session_pause(struct media_session *session)
LeaveCriticalSection(&session->cs);
}
+static void session_stop(struct media_session *session)
+{
+ HRESULT hr = S_OK;
+
+ EnterCriticalSection(&session->cs);
+
+ switch (session->state)
+ {
+ case SESSION_STATE_RUNNING:
+ case SESSION_STATE_PAUSED:
+
+ /* Transition in two steps - pause clock, wait for sinks and pause sources. */
+ if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock)))
+ session->state = SESSION_STATE_STOPPING_SINKS;
+
+ break;
+ default:
+ ;
+ }
+
+ if (FAILED(hr))
+ {
+ session->state = SESSION_STATE_STOPPED;
+ IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStopped, &GUID_NULL, hr, NULL);
+ }
+
+ LeaveCriticalSection(&session->cs);
+}
+
+
static struct media_source *session_get_media_source(struct media_session *session, IMFMediaSource *source)
{
struct media_source *cur;
@@ -1503,6 +1535,9 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface,
case SESSION_CMD_PAUSE:
session_pause(session);
break;
+ case SESSION_CMD_STOP:
+ session_stop(session);
+ break;
case SESSION_CMD_CLOSE:
EnterCriticalSection(&session->cs);
if (session->state != SESSION_STATE_CLOSED)
@@ -1724,6 +1759,7 @@ static void session_set_source_object_state(struct media_session *session, IUnkn
MediaEventType event_type)
{
struct source_node *src_node;
+ struct output_node *out_node;
struct media_source *src;
enum object_state state;
BOOL changed = FALSE;
@@ -1788,6 +1824,22 @@ static void session_set_source_object_state(struct media_session *session, IUnkn
IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionPaused, &GUID_NULL, S_OK, NULL);
+ break;
+ case SESSION_STATE_STOPPING_SOURCES:
+ if (!session_is_source_nodes_state(session, OBJ_STATE_STOPPED))
+ break;
+
+ session->state = SESSION_STATE_STOPPED;
+
+ LIST_FOR_EACH_ENTRY(out_node, &session->presentation.output_nodes, struct output_node, entry)
+ {
+ IMFStreamSink_Flush(out_node->stream);
+ }
+
+ session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
+
+ IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStopped, &GUID_NULL, S_OK, NULL);
+
break;
default:
;
@@ -1870,6 +1922,25 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre
IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionPaused, &GUID_NULL, hr, NULL);
}
+ break;
+ case SESSION_STATE_STOPPING_SINKS:
+ if (!session_is_output_nodes_state(session, OBJ_STATE_STOPPED))
+ break;
+
+ session->state = SESSION_STATE_STOPPING_SOURCES;
+
+ LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
+ {
+ if (FAILED(hr = IMFMediaSource_Stop(source->source)))
+ break;
+ }
+
+ if (FAILED(hr))
+ {
+ session->state = SESSION_STATE_STOPPED;
+ IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStopped, &GUID_NULL, hr, NULL);
+ }
+
break;
default:
;
--
2.25.0
Feb. 28, 2020
[PATCH 13/14] mf: Allow restarting from paused state.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mf/session.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index b2ddad6c96..485b336570 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -614,6 +614,7 @@ static void session_start(struct media_session *session, const GUID *time_format
switch (session->state)
{
case SESSION_STATE_STOPPED:
+ case SESSION_STATE_PAUSED:
session->presentation.time_format = *time_format;
session->presentation.start_position.vt = VT_EMPTY;
--
2.25.0
Feb. 28, 2020
[PATCH 12/14] mf: Implement Pause() command for media session.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mf/session.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 63 insertions(+)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index 70d042cf3d..b2ddad6c96 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -76,6 +76,9 @@ enum session_state
SESSION_STATE_STARTING_SOURCES,
SESSION_STATE_STARTING_SINKS,
SESSION_STATE_RUNNING,
+ SESSION_STATE_PAUSING_SINKS,
+ SESSION_STATE_PAUSING_SOURCES,
+ SESSION_STATE_PAUSED,
SESSION_STATE_CLOSED,
SESSION_STATE_SHUT_DOWN,
};
@@ -644,6 +647,34 @@ static void session_start(struct media_session *session, const GUID *time_format
LeaveCriticalSection(&session->cs);
}
+static void session_pause(struct media_session *session)
+{
+ HRESULT hr;
+
+ EnterCriticalSection(&session->cs);
+
+ switch (session->state)
+ {
+ case SESSION_STATE_RUNNING:
+
+ /* Transition in two steps - pause clock, wait for sinks and pause sources. */
+ if (SUCCEEDED(hr = IMFPresentationClock_Pause(session->clock)))
+ session->state = SESSION_STATE_PAUSING_SINKS;
+
+ break;
+ default:
+ hr = MF_E_INVALIDREQUEST;
+ }
+
+ if (FAILED(hr))
+ {
+ session->state = SESSION_STATE_PAUSED;
+ IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionPaused, &GUID_NULL, hr, NULL);
+ }
+
+ LeaveCriticalSection(&session->cs);
+}
+
static struct media_source *session_get_media_source(struct media_session *session, IMFMediaSource *source)
{
struct media_source *cur;
@@ -1469,6 +1500,7 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface,
session_start(session, &op->u.start.time_format, &op->u.start.start_position);
break;
case SESSION_CMD_PAUSE:
+ session_pause(session);
break;
case SESSION_CMD_CLOSE:
EnterCriticalSection(&session->cs);
@@ -1744,6 +1776,17 @@ static void session_set_source_object_state(struct media_session *session, IUnkn
if (SUCCEEDED(session_start_clock(session)))
session->state = SESSION_STATE_STARTING_SINKS;
+ break;
+ case SESSION_STATE_PAUSING_SOURCES:
+ if (!session_is_source_nodes_state(session, OBJ_STATE_PAUSED))
+ break;
+
+ session->state = SESSION_STATE_PAUSED;
+
+ session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE);
+
+ IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionPaused, &GUID_NULL, S_OK, NULL);
+
break;
default:
;
@@ -1759,6 +1802,7 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre
BOOL changed = FALSE;
IMFMediaEvent *event;
DWORD caps, flags;
+ HRESULT hr;
if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
return;
@@ -1806,6 +1850,25 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre
IMFMediaEventQueue_QueueEvent(session->event_queue, event);
IMFMediaEvent_Release(event);
}
+ break;
+ case SESSION_STATE_PAUSING_SINKS:
+ if (!session_is_output_nodes_state(session, OBJ_STATE_PAUSED))
+ break;
+
+ session->state = SESSION_STATE_PAUSING_SOURCES;
+
+ LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
+ {
+ if (FAILED(hr = IMFMediaSource_Pause(source->source)))
+ break;
+ }
+
+ if (FAILED(hr))
+ {
+ session->state = SESSION_STATE_PAUSED;
+ IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionPaused, &GUID_NULL, hr, NULL);
+ }
+
break;
default:
;
--
2.25.0
Feb. 28, 2020
[PATCH 11/14] mf: Track stream sinks state to maintain session state.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mf/session.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 84 insertions(+)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index 367f39cd9c..70d042cf3d 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -1582,6 +1582,19 @@ static BOOL session_is_source_nodes_state(struct media_session *session, enum ob
return TRUE;
}
+static BOOL session_is_output_nodes_state(struct media_session *session, enum object_state state)
+{
+ struct output_node *node;
+
+ LIST_FOR_EACH_ENTRY(node, &session->presentation.output_nodes, struct output_node, entry)
+ {
+ if (node->state != state)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static enum object_state session_get_object_state_for_event(MediaEventType event)
{
switch (event)
@@ -1737,6 +1750,68 @@ static void session_set_source_object_state(struct media_session *session, IUnkn
}
}
+static void session_set_sink_stream_state(struct media_session *session, IMFStreamSink *stream,
+ MediaEventType event_type)
+{
+ struct media_source *source;
+ struct output_node *node;
+ enum object_state state;
+ BOOL changed = FALSE;
+ IMFMediaEvent *event;
+ DWORD caps, flags;
+
+ if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
+ return;
+
+ LIST_FOR_EACH_ENTRY(node, &session->presentation.output_nodes, struct output_node, entry)
+ {
+ if (stream == node->stream)
+ {
+ changed = node->state != state;
+ node->state = state;
+ break;
+ }
+ }
+
+ if (!changed)
+ return;
+
+ switch (session->state)
+ {
+ case SESSION_STATE_STARTING_SINKS:
+ if (!session_is_output_nodes_state(session, OBJ_STATE_STARTED))
+ break;
+
+ session->state = SESSION_STATE_RUNNING;
+
+ caps = session->caps | MFSESSIONCAP_PAUSE;
+
+ LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
+ {
+ if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source->source, &flags)))
+ {
+ if (!(flags & MFMEDIASOURCE_CAN_PAUSE))
+ {
+ caps &= ~MFSESSIONCAP_PAUSE;
+ break;
+ }
+ }
+ }
+
+ session_set_caps(session, caps);
+
+ if (SUCCEEDED(MFCreateMediaEvent(MESessionStarted, &GUID_NULL, S_OK, NULL, &event)))
+ {
+ IMFMediaEvent_SetUINT64(event, &MF_EVENT_PRESENTATION_TIME_OFFSET, 0);
+ IMFMediaEventQueue_QueueEvent(session->event_queue, event);
+ IMFMediaEvent_Release(event);
+ }
+ break;
+ default:
+ ;
+ }
+}
+
static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
{
struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
@@ -1803,6 +1878,15 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM
IMFMediaSource_Release(source);
+ break;
+ case MEStreamSinkStarted:
+ case MEStreamSinkPaused:
+ case MEStreamSinkStopped:
+
+ EnterCriticalSection(&session->cs);
+ session_set_sink_stream_state(session, (IMFStreamSink *)event_source, event_type);
+ LeaveCriticalSection(&session->cs);
+
break;
default:
;
--
2.25.0
Feb. 28, 2020
[PATCH 10/14] mf: Implement two-step session transition to running state.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mf/session.c | 313 +++++++++++++++++++++++++++-------------------
1 file changed, 186 insertions(+), 127 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index cbaa2bf23a..367f39cd9c 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -73,7 +73,8 @@ struct queued_topology
enum session_state
{
SESSION_STATE_STOPPED = 0,
- SESSION_STATE_STARTING,
+ SESSION_STATE_STARTING_SOURCES,
+ SESSION_STATE_STARTING_SINKS,
SESSION_STATE_RUNNING,
SESSION_STATE_CLOSED,
SESSION_STATE_SHUT_DOWN,
@@ -101,6 +102,7 @@ struct source_node
IMFMediaStream *stream;
IMFMediaSource *source;
DWORD stream_id;
+ enum object_state state;
};
struct media_sink
@@ -117,6 +119,12 @@ struct output_node
enum object_state state;
};
+enum presentation_flags
+{
+ SESSION_FLAG_SOURCES_SUBSCRIBED = 0x1,
+ SESSION_FLAG_SINKS_SUBSCRIBED = 0x2,
+};
+
struct media_session
{
IMFMediaSession IMFMediaSession_iface;
@@ -128,6 +136,7 @@ struct media_session
LONG refcount;
IMFMediaEventQueue *event_queue;
IMFPresentationClock *clock;
+ IMFPresentationTimeSource *system_time_source;
IMFRateControl *clock_rate_control;
IMFTopoLoader *topo_loader;
IMFQualityManager *quality_manager;
@@ -139,6 +148,11 @@ struct media_session
struct list source_nodes;
struct list sinks;
struct list output_nodes;
+ DWORD flags;
+
+ /* Latest Start() arguments. */
+ GUID time_format;
+ PROPVARIANT start_position;
} presentation;
struct list topologies;
enum session_state state;
@@ -589,9 +603,7 @@ 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;
- IMFCollection *nodes;
- DWORD count, i;
+ struct media_source *source;
HRESULT hr;
EnterCriticalSection(&session->cs);
@@ -600,60 +612,27 @@ static void session_start(struct media_session *session, const GUID *time_format
{
case SESSION_STATE_STOPPED:
- if (FAILED(IMFTopology_GetSourceNodeCollection(session->presentation.current_topology, &nodes)))
- break;
-
- if (FAILED(IMFCollection_GetElementCount(nodes, &count)))
- break;
+ session->presentation.time_format = *time_format;
+ session->presentation.start_position.vt = VT_EMPTY;
+ PropVariantCopy(&session->presentation.start_position, start_position);
- for (i = 0; i < count; ++i)
+ LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
{
- if (SUCCEEDED(hr = IMFCollection_GetElement(nodes, i, (IUnknown **)&node)))
+ if (!(session->presentation.flags & SESSION_FLAG_SOURCES_SUBSCRIBED))
{
- IMFPresentationDescriptor *pd = NULL;
- struct media_source *source;
-
- if (!(source = heap_alloc_zero(sizeof(*source))))
- hr = E_OUTOFMEMORY;
-
- if (SUCCEEDED(hr))
- hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_SOURCE, &IID_IMFMediaSource,
- (void **)&source->source);
-
- if (SUCCEEDED(hr))
- hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR,
- &IID_IMFPresentationDescriptor, (void **)&pd);
-
- /* Subscribe to source events, start it. */
- if (SUCCEEDED(hr))
- hr = IMFMediaSource_BeginGetEvent(source->source, &session->events_callback,
- (IUnknown *)source->source);
-
- if (SUCCEEDED(hr))
- hr = IMFMediaSource_Start(source->source, pd, time_format, start_position);
-
- if (pd)
- IMFPresentationDescriptor_Release(pd);
-
- if (SUCCEEDED(hr))
- {
- list_add_tail(&session->presentation.sources, &source->entry);
- }
- else if (source)
+ if (FAILED(hr = IMFMediaSource_BeginGetEvent(source->source, &session->events_callback,
+ (IUnknown *)source->source)))
{
- if (source->source)
- IMFMediaSource_Release(source->source);
- heap_free(source);
+ WARN("Failed to subscribe to source events, hr %#x.\n", hr);
}
-
- IMFTopologyNode_Release(node);
}
- }
- session->state = SESSION_STATE_STARTING;
-
- IMFCollection_Release(nodes);
+ if (FAILED(hr = IMFMediaSource_Start(source->source, source->pd, &GUID_NULL, start_position)))
+ WARN("Failed to start media source %p, hr %#x.\n", source->source, hr);
+ }
+ session->presentation.flags |= SESSION_FLAG_SOURCES_SUBSCRIBED;
+ session->state = SESSION_STATE_STARTING_SOURCES;
break;
case SESSION_STATE_RUNNING:
FIXME("Seeking is not implemented.\n");
@@ -1122,6 +1101,8 @@ static ULONG WINAPI mfsession_Release(IMFMediaSession *iface)
IMFMediaEventQueue_Release(session->event_queue);
if (session->clock)
IMFPresentationClock_Release(session->clock);
+ if (session->system_time_source)
+ IMFPresentationTimeSource_Release(session->system_time_source);
if (session->clock_rate_control)
IMFRateControl_Release(session->clock_rate_control);
if (session->topo_loader)
@@ -1485,10 +1466,8 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface,
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);
break;
- }
case SESSION_CMD_PAUSE:
break;
case SESSION_CMD_CLOSE:
@@ -1583,98 +1562,191 @@ 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 object_state state)
+static BOOL session_is_source_nodes_state(struct media_session *session, enum object_state state)
{
- struct media_source *cur;
- BOOL ret = TRUE;
+ struct media_source *source;
+ struct source_node *node;
- LIST_FOR_EACH_ENTRY(cur, &session->presentation.sources, struct media_source, entry)
+ LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
{
- if (source == cur->source)
- cur->state = state;
- ret &= cur->state == state;
+ if (source->state != state)
+ return FALSE;
+ }
+
+ LIST_FOR_EACH_ENTRY(node, &session->presentation.source_nodes, struct source_node, entry)
+ {
+ if (node->state != state)
+ return FALSE;
}
- return ret;
+ return TRUE;
}
-static HRESULT session_set_sinks_clock(struct media_session *session)
+static enum object_state session_get_object_state_for_event(MediaEventType event)
{
- IMFTopology *topology = session->presentation.current_topology;
- IMFTopologyNode *node;
- IMFCollection *nodes;
- DWORD count, i;
+ switch (event)
+ {
+ case MESourceStarted:
+ case MEStreamStarted:
+ case MEStreamSinkStarted:
+ return OBJ_STATE_STARTED;
+ case MESourcePaused:
+ case MEStreamPaused:
+ case MEStreamSinkPaused:
+ return OBJ_STATE_PAUSED;
+ case MESourceStopped:
+ case MEStreamStopped:
+ case MEStreamSinkStopped:
+ return OBJ_STATE_STOPPED;
+ default:
+ return OBJ_STATE_INVALID;
+ }
+}
+
+static HRESULT session_start_clock(struct media_session *session)
+{
+ IMFPresentationTimeSource *time_source = NULL;
+ LONGLONG start_offset = 0;
+ struct output_node *node;
+ struct media_sink *sink;
HRESULT hr;
- if (!list_empty(&session->presentation.sinks))
- return S_OK;
+ if (!(session->presentation.flags & SESSION_FLAG_SINKS_SUBSCRIBED))
+ {
+ LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
+ {
+ if (SUCCEEDED(IMFMediaSink_QueryInterface(sink->sink, &IID_IMFPresentationTimeSource,
+ (void **)&time_source)))
+ break;
+ }
- if (FAILED(hr = IMFTopology_GetOutputNodeCollection(topology, &nodes)))
- return hr;
+ if (time_source)
+ {
+ hr = IMFPresentationClock_SetTimeSource(session->clock, time_source);
+ IMFPresentationTimeSource_Release(time_source);
+ }
+ else
+ hr = IMFPresentationClock_SetTimeSource(session->clock, session->system_time_source);
- if (FAILED(hr = IMFCollection_GetElementCount(nodes, &count)))
- {
- IMFCollection_Release(nodes);
- return hr;
+ if (FAILED(hr))
+ WARN("Failed to set time source, hr %#x.\n", hr);
+
+ LIST_FOR_EACH_ENTRY(node, &session->presentation.output_nodes, struct output_node, entry)
+ {
+ if (FAILED(hr = IMFStreamSink_BeginGetEvent(node->stream, &session->events_callback,
+ (IUnknown *)node->stream)))
+ {
+ WARN("Failed to subscribe to stream sink events, hr %#x.\n", hr);
+ }
+ }
+
+ LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
+ {
+ if (sink->event_generator && FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(sink->event_generator,
+ &session->events_callback, (IUnknown *)sink->event_generator)))
+ {
+ WARN("Failed to subscribe to sink events, hr %#x.\n", hr);
+ }
+
+ if (FAILED(hr = IMFMediaSink_SetPresentationClock(sink->sink, session->clock)))
+ WARN("Failed to set presentation clock for the sink, hr %#x.\n", hr);
+ }
+
+ session->presentation.flags |= SESSION_FLAG_SINKS_SUBSCRIBED;
}
- for (i = 0; i < count; ++i)
+ if (IsEqualGUID(&session->presentation.time_format, &GUID_NULL))
{
- IMFStreamSink *stream_sink = NULL;
- struct media_sink *sink;
-
- if (FAILED(hr = IMFCollection_GetElement(nodes, i, (IUnknown **)&node)))
- break;
+ if (session->presentation.start_position.vt == VT_EMPTY)
+ start_offset = PRESENTATION_CURRENT_POSITION;
+ else if (session->presentation.start_position.vt == VT_I8)
+ start_offset = session->presentation.start_position.hVal.QuadPart;
+ else
+ FIXME("Unhandled position type %d.\n", session->presentation.start_position.vt);
+ }
+ else
+ FIXME("Unhandled time format %s.\n", debugstr_guid(&session->presentation.time_format));
- if (!(sink = heap_alloc_zero(sizeof(*sink))))
- hr = E_OUTOFMEMORY;
+ if (FAILED(hr = IMFPresentationClock_Start(session->clock, start_offset)))
+ WARN("Failed to start session clock, hr %#x.\n", hr);
- if (SUCCEEDED(hr))
- hr = IMFTopologyNode_GetObject(node, (IUnknown **)&stream_sink);
+ return hr;
+}
- if (SUCCEEDED(hr))
- hr = IMFStreamSink_GetMediaSink(stream_sink, &sink->sink);
- if (SUCCEEDED(hr))
- hr = IMFMediaSink_SetPresentationClock(sink->sink, session->clock);
+static void session_set_source_object_state(struct media_session *session, IUnknown *object,
+ MediaEventType event_type)
+{
+ struct source_node *src_node;
+ struct media_source *src;
+ enum object_state state;
+ BOOL changed = FALSE;
- if (SUCCEEDED(hr))
- hr = IMFStreamSink_BeginGetEvent(stream_sink, &session->events_callback, (IUnknown *)stream_sink);
+ if ((state = session_get_object_state_for_event(event_type)) == OBJ_STATE_INVALID)
+ return;
- if (stream_sink)
- IMFStreamSink_Release(stream_sink);
+ switch (event_type)
+ {
+ case MESourceStarted:
+ case MESourcePaused:
+ case MESourceStopped:
- if (SUCCEEDED(hr))
- {
- list_add_tail(&session->presentation.sinks, &sink->entry);
- }
- else if (sink)
- {
- if (sink->sink)
- IMFMediaSink_Release(sink->sink);
- heap_free(sink);
- }
+ LIST_FOR_EACH_ENTRY(src, &session->presentation.sources, struct media_source, entry)
+ {
+ if (object == (IUnknown *)src->source)
+ {
+ changed = src->state != state;
+ src->state = state;
+ break;
+ }
+ }
+ break;
+ case MEStreamStarted:
+ case MEStreamPaused:
+ case MEStreamStopped:
- IMFTopologyNode_Release(node);
+ LIST_FOR_EACH_ENTRY(src_node, &session->presentation.source_nodes, struct source_node, entry)
+ {
+ if (object == (IUnknown *)src_node->stream)
+ {
+ changed = src_node->state != state;
+ src_node->state = state;
+ break;
+ }
+ }
+ default:
+ ;
}
- IMFCollection_Release(nodes);
+ if (!changed)
+ return;
- return hr;
+ switch (session->state)
+ {
+ case SESSION_STATE_STARTING_SOURCES:
+ if (!session_is_source_nodes_state(session, OBJ_STATE_STARTED))
+ break;
+
+ session_set_topo_status(session, S_OK, MF_TOPOSTATUS_STARTED_SOURCE);
+ if (SUCCEEDED(session_start_clock(session)))
+ session->state = SESSION_STATE_STARTING_SINKS;
+
+ break;
+ default:
+ ;
+ }
}
static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
{
struct media_session *session = impl_from_events_callback_IMFAsyncCallback(iface);
IMFMediaEventGenerator *event_source;
- enum object_state source_state;
IMFMediaEvent *event = NULL;
MediaEventType event_type;
IMFMediaSource *source;
IMFMediaStream *stream;
PROPVARIANT value;
HRESULT hr;
- BOOL ret;
if (FAILED(hr = IMFAsyncResult_GetState(result, (IUnknown **)&event_source)))
return hr;
@@ -1703,30 +1775,14 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM
case MESourceStarted:
case MESourcePaused:
case MESourceStopped:
- if (event_type == MESourceStarted)
- source_state = OBJ_STATE_STARTED;
- else if (event_type == MESourcePaused)
- source_state = OBJ_STATE_PAUSED;
- else
- source_state = OBJ_STATE_STOPPED;
+ case MEStreamStarted:
+ case MEStreamPaused:
+ case MEStreamStopped:
EnterCriticalSection(&session->cs);
-
- ret = session_set_source_state(session, (IMFMediaSource *)event_source, source_state);
- if (ret && event_type == MESourceStarted)
- {
- session_set_topo_status(session, S_OK, MF_TOPOSTATUS_STARTED_SOURCE);
-
- if (session->state == SESSION_STATE_STARTING)
- {
- if (SUCCEEDED(session_set_sinks_clock(session)))
- {
- session->state = SESSION_STATE_RUNNING;
- }
- }
- }
-
+ session_set_source_object_state(session, (IUnknown *)event_source, event_type);
LeaveCriticalSection(&session->cs);
+
break;
case MENewStream:
stream = (IMFMediaStream *)value.punkVal;
@@ -1961,6 +2017,9 @@ HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **ses
if (FAILED(hr = MFCreatePresentationClock(&object->clock)))
goto failed;
+ if (FAILED(hr = MFCreateSystemTimeSource(&object->system_time_source)))
+ goto failed;
+
if (FAILED(hr = IMFPresentationClock_QueryInterface(object->clock, &IID_IMFRateControl,
(void **)&object->clock_rate_control)))
{
--
2.25.0
Feb. 28, 2020
[PATCH 09/14] mf: Add support for MESessionCapabilitiesChanged event.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mf/session.c | 105 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 103 insertions(+), 2 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index 0bbf0bac56..cbaa2bf23a 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -142,6 +142,7 @@ struct media_session
} presentation;
struct list topologies;
enum session_state state;
+ DWORD caps;
CRITICAL_SECTION cs;
};
@@ -798,6 +799,50 @@ static void session_raise_topology_set(struct media_session *session, IMFTopolog
IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologySet, &GUID_NULL, status, ¶m);
}
+static DWORD session_get_object_rate_caps(IUnknown *object)
+{
+ IMFRateSupport *rate_support;
+ DWORD caps = 0;
+ float rate;
+
+ if (SUCCEEDED(MFGetService(object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support)))
+ {
+ rate = 0.0f;
+ if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support, MFRATE_FORWARD, TRUE, &rate)) && rate != 0.0f)
+ caps |= MFSESSIONCAP_RATE_FORWARD;
+
+ rate = 0.0f;
+ if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support, MFRATE_REVERSE, TRUE, &rate)) && rate != 0.0f)
+ caps |= MFSESSIONCAP_RATE_REVERSE;
+
+ IMFRateSupport_Release(rate_support);
+ }
+
+ return caps;
+}
+
+static void session_set_caps(struct media_session *session, DWORD caps)
+{
+ DWORD delta = session->caps ^ caps;
+ IMFMediaEvent *event;
+
+ /* Delta is documented to reflect rate value changes as well, but it's not clear what to compare
+ them to, since session always queries for current object rates. */
+ if (!delta)
+ return;
+
+ session->caps = caps;
+
+ if (FAILED(MFCreateMediaEvent(MESessionCapabilitiesChanged, &GUID_NULL, S_OK, NULL, &event)))
+ return;
+
+ IMFMediaEvent_SetUINT32(event, &MF_EVENT_SESSIONCAPS, caps);
+ IMFMediaEvent_SetUINT32(event, &MF_EVENT_SESSIONCAPS_DELTA, delta);
+
+ IMFMediaEventQueue_QueueEvent(session->event_queue, event);
+ IMFMediaEvent_Release(event);
+}
+
static HRESULT session_add_media_sink(struct media_session *session, IMFTopologyNode *node, IMFMediaSink *sink)
{
struct media_sink *media_sink;
@@ -885,6 +930,9 @@ static HRESULT session_collect_output_nodes(struct media_session *session)
static void session_set_current_topology(struct media_session *session, IMFTopology *topology)
{
+ struct media_source *source;
+ DWORD caps, object_flags;
+ struct media_sink *sink;
IMFMediaEvent *event;
HRESULT hr;
@@ -907,6 +955,46 @@ static void session_set_current_topology(struct media_session *session, IMFTopol
IMFMediaEventQueue_QueueEvent(session->event_queue, event);
IMFMediaEvent_Release(event);
}
+
+ /* Update session caps. */
+ caps = MFSESSIONCAP_START | MFSESSIONCAP_SEEK | MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE |
+ MFSESSIONCAP_DOES_NOT_USE_NETWORK;
+
+ LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry)
+ {
+ if (!caps)
+ break;
+
+ object_flags = 0;
+ if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source->source, &object_flags)))
+ {
+ if (!(object_flags & MFMEDIASOURCE_DOES_NOT_USE_NETWORK))
+ caps &= ~MFSESSIONCAP_DOES_NOT_USE_NETWORK;
+ if (!(object_flags & MFMEDIASOURCE_CAN_SEEK))
+ caps &= ~MFSESSIONCAP_SEEK;
+ }
+
+ /* Mask unsupported rate caps. */
+
+ caps &= session_get_object_rate_caps((IUnknown *)source->source)
+ | ~(MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE);
+ }
+
+ LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry)
+ {
+ if (!caps)
+ break;
+
+ object_flags = 0;
+ if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink->sink, &object_flags)))
+ {
+ if (!(object_flags & MEDIASINK_RATELESS))
+ caps &= session_get_object_rate_caps((IUnknown *)sink->sink)
+ | ~(MFSESSIONCAP_RATE_FORWARD | MFSESSIONCAP_RATE_REVERSE);
+ }
+ }
+
+ session_set_caps(session, caps);
}
static void session_set_topology(struct media_session *session, DWORD flags, IMFTopology *topology)
@@ -1242,9 +1330,22 @@ static HRESULT WINAPI mfsession_GetClock(IMFMediaSession *iface, IMFClock **cloc
static HRESULT WINAPI mfsession_GetSessionCapabilities(IMFMediaSession *iface, DWORD *caps)
{
- FIXME("%p, %p.\n", iface, caps);
+ struct media_session *session = impl_from_IMFMediaSession(iface);
+ HRESULT hr = S_OK;
- return E_NOTIMPL;
+ TRACE("%p, %p.\n", iface, caps);
+
+ if (!caps)
+ return E_POINTER;
+
+ EnterCriticalSection(&session->cs);
+ if (session->state == SESSION_STATE_SHUT_DOWN)
+ hr = MF_E_SHUTDOWN;
+ else
+ *caps = session->caps;
+ LeaveCriticalSection(&session->cs);
+
+ return hr;
}
static HRESULT WINAPI mfsession_GetFullTopology(IMFMediaSession *iface, DWORD flags, TOPOID id, IMFTopology **topology)
--
2.25.0
Feb. 28, 2020