Nikolay Sivov : mf: Add support for MESessionCapabilitiesChanged event.

Alexandre Julliard julliard at winehq.org
Fri Feb 28 13:54:41 CST 2020


Module: wine
Branch: master
Commit: 9eb7337a58bcd32df318c0cf4b6a44cc57e5ae89
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=9eb7337a58bcd32df318c0cf4b6a44cc57e5ae89

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Fri Feb 28 15:00:59 2020 +0300

mf: Add support for MESessionCapabilitiesChanged event.

Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 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, &param);
 }
 
+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)




More information about the wine-cvs mailing list