Nikolay Sivov : mfplay: Partially implement SetMediaItem().

Alexandre Julliard julliard at winehq.org
Tue Apr 13 16:31:20 CDT 2021


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

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Tue Apr 13 09:03:28 2021 +0300

mfplay: Partially implement SetMediaItem().

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

---

 dlls/mfplay/player.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 132 insertions(+), 6 deletions(-)

diff --git a/dlls/mfplay/player.c b/dlls/mfplay/player.c
index 0c72395ab1e..7360042ee54 100644
--- a/dlls/mfplay/player.c
+++ b/dlls/mfplay/player.c
@@ -19,6 +19,7 @@
 #define COBJMACROS
 
 #include <stdarg.h>
+#include <assert.h>
 
 #include "windef.h"
 #include "winbase.h"
@@ -28,8 +29,12 @@
 
 #include "wine/debug.h"
 
+#include "initguid.h"
+
 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
 
+DEFINE_GUID(_MF_TOPO_MEDIA_ITEM, 0x6c1bb4df, 0x59ba, 0x4020, 0x85, 0x0c, 0x35, 0x79, 0xa2, 0x7a, 0xe2, 0x51);
+
 static const WCHAR eventclassW[] = L"MediaPlayerEventCallbackClass";
 
 static LONG startup_refcount;
@@ -549,6 +554,14 @@ static const IMFPMediaItemVtbl media_item_vtbl =
     media_item_GetMetadata,
 };
 
+static struct media_item *unsafe_impl_from_IMFPMediaItem(IMFPMediaItem *iface)
+{
+    if (!iface)
+        return NULL;
+    assert(iface->lpVtbl == (IMFPMediaItemVtbl *)&media_item_vtbl);
+    return CONTAINING_RECORD(iface, struct media_item, IMFPMediaItem_iface);
+}
+
 static HRESULT create_media_item(IMFPMediaPlayer *player, DWORD_PTR user_data, struct media_item **item)
 {
     struct media_item *object;
@@ -822,11 +835,106 @@ static HRESULT WINAPI media_player_CreateMediaItemFromObject(IMFPMediaPlayer *if
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI media_player_SetMediaItem(IMFPMediaPlayer *iface, IMFPMediaItem *item)
+static HRESULT media_item_get_stream_type(IMFStreamDescriptor *sd, GUID *major)
 {
-    FIXME("%p, %p.\n", iface, item);
+    IMFMediaTypeHandler *handler;
+    HRESULT hr;
 
-    return E_NOTIMPL;
+    if (SUCCEEDED(hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler)))
+    {
+        hr = IMFMediaTypeHandler_GetMajorType(handler, major);
+        IMFMediaTypeHandler_Release(handler);
+    }
+
+    return hr;
+}
+
+static HRESULT media_item_create_topology(struct media_player *player, struct media_item *item, IMFTopology **out)
+{
+    IMFTopologyNode *src_node, *sink_node;
+    IMFActivate *sar_activate;
+    IMFStreamDescriptor *sd;
+    IMFTopology *topology;
+    unsigned int idx;
+    BOOL selected;
+    HRESULT hr;
+    GUID major;
+
+    if (FAILED(hr = MFCreateTopology(&topology)))
+        return hr;
+
+    /* FIXME: handle user sinks */
+
+    /* Use first stream if none selected. */
+    if (player->output_window)
+    {
+        FIXME("Video streams are not handled.\n");
+    }
+
+    /* Set up audio branches for all selected streams. */
+
+    idx = 0;
+    while (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, idx++, &selected, &sd)))
+    {
+        if (selected && SUCCEEDED(media_item_get_stream_type(sd, &major)) && IsEqualGUID(&major, &MFMediaType_Audio))
+        {
+            if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &src_node)))
+            {
+                IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_SOURCE, (IUnknown *)item->source);
+                IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)item->pd);
+                IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd);
+
+                IMFTopology_AddNode(topology, src_node);
+            }
+
+            if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &sink_node)))
+            {
+                if (SUCCEEDED(MFCreateAudioRendererActivate(&sar_activate)))
+                {
+                    IMFTopologyNode_SetObject(sink_node, (IUnknown *)sar_activate);
+                    IMFActivate_Release(sar_activate);
+                }
+
+                IMFTopology_AddNode(topology, sink_node);
+            }
+
+            if (src_node && sink_node)
+                IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0);
+
+            if (src_node)
+                IMFTopologyNode_Release(src_node);
+            if (sink_node)
+                IMFTopologyNode_Release(sink_node);
+        }
+
+        IMFStreamDescriptor_Release(sd);
+    }
+
+    *out = topology;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI media_player_SetMediaItem(IMFPMediaPlayer *iface, IMFPMediaItem *item_iface)
+{
+    struct media_player *player = impl_from_IMFPMediaPlayer(iface);
+    struct media_item *item = unsafe_impl_from_IMFPMediaItem(item_iface);
+    IMFTopology *topology;
+    HRESULT hr;
+
+    TRACE("%p, %p.\n", iface, item_iface);
+
+    if (item->player != iface)
+        return E_INVALIDARG;
+
+    if (FAILED(hr = media_item_create_topology(player, item, &topology)))
+        return hr;
+
+    IMFTopology_SetUnknown(topology, &_MF_TOPO_MEDIA_ITEM, (IUnknown *)item_iface);
+    hr = IMFMediaSession_SetTopology(player->session, MFSESSION_SETTOPOLOGY_IMMEDIATE, topology);
+    IMFTopology_Release(topology);
+
+    return hr;
 }
 
 static HRESULT WINAPI media_player_ClearMediaItem(IMFPMediaPlayer *iface)
@@ -1267,6 +1375,8 @@ static HRESULT WINAPI media_player_session_events_callback_Invoke(IMFAsyncCallba
     MFP_MEDIAPLAYER_STATE state;
     MFP_EVENT_TYPE event_type;
     HRESULT hr, event_status;
+    IMFPMediaItem *item = NULL;
+    IMFTopology *topology;
 
     if (FAILED(hr = IMFMediaSession_EndGetEvent(player->session, result, &session_event)))
         return S_OK;
@@ -1274,6 +1384,12 @@ static HRESULT WINAPI media_player_session_events_callback_Invoke(IMFAsyncCallba
     IMFMediaEvent_GetType(session_event, &session_event_type);
     IMFMediaEvent_GetStatus(session_event, &event_status);
 
+    if (SUCCEEDED(IMFMediaSession_GetFullTopology(player->session, MFSESSION_GETFULLTOPOLOGY_CURRENT, 0, &topology)))
+    {
+        IMFTopology_GetUnknown(topology, &_MF_TOPO_MEDIA_ITEM, &IID_IMFPMediaItem, (void **)&item);
+        IMFTopology_Release(topology);
+    }
+
     switch (session_event_type)
     {
         case MESessionStarted:
@@ -1302,17 +1418,27 @@ static HRESULT WINAPI media_player_session_events_callback_Invoke(IMFAsyncCallba
 
             /* FIXME: set pMediaItem */
             media_player_queue_event(player, event);
-            IUnknown_Release(&event->IUnknown_iface);
+
+            break;
+
+        case MESessionTopologySet:
+
+            media_event_create(player, MFP_EVENT_TYPE_MEDIAITEM_SET, event_status, &event);
+            event->u.generic.item = item;
+            if (event->u.generic.item)
+                IMFPMediaItem_AddRef(event->u.generic.item);
+            media_player_queue_event(player, event);
 
             break;
         default:
             ;
     }
 
+    if (item)
+        IMFPMediaItem_Release(item);
+
     if (event)
-    {
         IUnknown_Release(&event->IUnknown_iface);
-    }
 
     IMFMediaSession_BeginGetEvent(player->session, &player->session_events_callback, NULL);
     IMFMediaEvent_Release(session_event);




More information about the wine-cvs mailing list