mf: Add support for MESessionCapabilitiesChanged event.

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:59 +03:00 committed by Alexandre Julliard
parent c61219625c
commit 9eb7337a58
1 changed files with 103 additions and 2 deletions

View File

@ -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)