[PATCH 6/7] mfplay: Add support for async user callback.

Nikolay Sivov nsivov at codeweavers.com
Tue Apr 6 02:25:31 CDT 2021


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/mfplay/player.c | 222 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 216 insertions(+), 6 deletions(-)

diff --git a/dlls/mfplay/player.c b/dlls/mfplay/player.c
index 5a85d9f0505..c08f496b508 100644
--- a/dlls/mfplay/player.c
+++ b/dlls/mfplay/player.c
@@ -59,10 +59,41 @@ struct media_player
     IMFPMediaPlayer IMFPMediaPlayer_iface;
     IPropertyStore IPropertyStore_iface;
     IMFAsyncCallback resolver_callback;
+    IMFAsyncCallback events_callback;
     LONG refcount;
     IMFPMediaPlayerCallback *callback;
     IPropertyStore *propstore;
     IMFSourceResolver *resolver;
+    MFP_CREATION_OPTIONS options;
+};
+
+struct generic_event
+{
+    MFP_EVENT_HEADER header;
+    IMFPMediaItem *item;
+};
+
+struct media_event
+{
+    IUnknown IUnknown_iface;
+    LONG refcount;
+    union
+    {
+        MFP_EVENT_HEADER header;
+        struct generic_event generic;
+        MFP_PLAY_EVENT play;
+        MFP_PAUSE_EVENT pause;
+        MFP_STOP_EVENT stop;
+        MFP_POSITION_SET_EVENT position_set;
+        MFP_RATE_SET_EVENT rate_set;
+        MFP_MEDIAITEM_CREATED_EVENT item_created;
+        MFP_MEDIAITEM_SET_EVENT item_set;
+        MFP_MEDIAITEM_CLEARED_EVENT item_cleared;
+        MFP_MF_EVENT event;
+        MFP_ERROR_EVENT error;
+        MFP_PLAYBACK_ENDED_EVENT ended;
+        MFP_ACQUIRE_USER_CREDENTIAL_EVENT acquire_creds;
+    } u;
 };
 
 static struct media_player *impl_from_IMFPMediaPlayer(IMFPMediaPlayer *iface)
@@ -80,11 +111,120 @@ static struct media_player *impl_from_resolver_IMFAsyncCallback(IMFAsyncCallback
     return CONTAINING_RECORD(iface, struct media_player, resolver_callback);
 }
 
+static struct media_player *impl_from_events_IMFAsyncCallback(IMFAsyncCallback *iface)
+{
+    return CONTAINING_RECORD(iface, struct media_player, events_callback);
+}
+
 static struct media_item *impl_from_IMFPMediaItem(IMFPMediaItem *iface)
 {
     return CONTAINING_RECORD(iface, struct media_item, IMFPMediaItem_iface);
 }
 
+static struct media_event *impl_event_from_IUnknown(IUnknown *iface)
+{
+    return CONTAINING_RECORD(iface, struct media_event, IUnknown_iface);
+}
+
+static HRESULT WINAPI media_event_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
+{
+    if (IsEqualIID(riid, &IID_IUnknown))
+    {
+        *obj = iface;
+        IUnknown_AddRef(iface);
+        return S_OK;
+    }
+
+    *obj = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI media_event_AddRef(IUnknown *iface)
+{
+    struct media_event *event = impl_event_from_IUnknown(iface);
+    ULONG refcount = InterlockedIncrement(&event->refcount);
+
+    TRACE("%p, refcount %u.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI media_event_Release(IUnknown *iface)
+{
+    struct media_event *event = impl_event_from_IUnknown(iface);
+    ULONG refcount = InterlockedDecrement(&event->refcount);
+
+    TRACE("%p, refcount %u.\n", iface, refcount);
+
+    if (!refcount)
+    {
+        if (event->u.header.pMediaPlayer)
+            IMFPMediaPlayer_Release(event->u.header.pMediaPlayer);
+        if (event->u.header.pPropertyStore)
+            IPropertyStore_Release(event->u.header.pPropertyStore);
+
+        switch (event->u.header.eEventType)
+        {
+            /* Most types share same layout. */
+            case MFP_EVENT_TYPE_PLAY:
+            case MFP_EVENT_TYPE_PAUSE:
+            case MFP_EVENT_TYPE_STOP:
+            case MFP_EVENT_TYPE_POSITION_SET:
+            case MFP_EVENT_TYPE_RATE_SET:
+            case MFP_EVENT_TYPE_MEDIAITEM_CREATED:
+            case MFP_EVENT_TYPE_MEDIAITEM_SET:
+            case MFP_EVENT_TYPE_FRAME_STEP:
+            case MFP_EVENT_TYPE_MEDIAITEM_CLEARED:
+            case MFP_EVENT_TYPE_PLAYBACK_ENDED:
+                if (event->u.generic.item)
+                    IMFPMediaItem_Release(event->u.generic.item);
+                break;
+            case MFP_EVENT_TYPE_MF:
+                if (event->u.event.pMFMediaEvent)
+                    IMFMediaEvent_Release(event->u.event.pMFMediaEvent);
+                if (event->u.event.pMediaItem)
+                    IMFPMediaItem_Release(event->u.event.pMediaItem);
+                break;
+            default:
+                FIXME("Unsupported event %u.\n", event->u.header.eEventType);
+                break;
+        }
+
+        heap_free(event);
+    }
+
+    return refcount;
+}
+
+static const IUnknownVtbl media_event_vtbl =
+{
+    media_event_QueryInterface,
+    media_event_AddRef,
+    media_event_Release,
+};
+
+static HRESULT media_event_create(MFP_EVENT_TYPE event_type, HRESULT hr,
+        IMFPMediaPlayer *player, struct media_event **event)
+{
+    struct media_event *object;
+
+    if (!(object = heap_alloc_zero(sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    object->IUnknown_iface.lpVtbl = &media_event_vtbl;
+    object->refcount = 1;
+    object->u.header.eEventType = event_type;
+    object->u.header.hrEvent = hr;
+    object->u.header.pMediaPlayer = player;
+    IMFPMediaPlayer_AddRef(object->u.header.pMediaPlayer);
+    /* FIXME: set player state field */
+    /* FIXME: set properties for some events? */
+
+    *event = object;
+
+    return S_OK;
+}
+
 static HRESULT WINAPI media_item_QueryInterface(IMFPMediaItem *iface, REFIID riid, void **obj)
 {
     TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
@@ -391,6 +531,18 @@ static HRESULT media_item_set_source(struct media_item *item, IUnknown *object)
     return hr;
 }
 
+static void media_player_queue_event(struct media_player *player, struct media_event *event)
+{
+    if (player->options & MFP_OPTION_FREE_THREADED_CALLBACK)
+    {
+        MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, &player->events_callback, &event->IUnknown_iface);
+    }
+    else
+    {
+        /* FIXME: same-thread callback notification */
+    }
+}
+
 static HRESULT WINAPI media_player_QueryInterface(IMFPMediaPlayer *iface, REFIID riid, void **obj)
 {
     struct media_player *player = impl_from_IMFPMediaPlayer(iface);
@@ -863,7 +1015,7 @@ static const IPropertyStoreVtbl media_player_propstore_vtbl =
     media_player_propstore_Commit,
 };
 
-static HRESULT WINAPI media_player_resolver_callback_QueryInterface(IMFAsyncCallback *iface,
+static HRESULT WINAPI media_player_callback_QueryInterface(IMFAsyncCallback *iface,
         REFIID riid, void **obj)
 {
     if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
@@ -890,7 +1042,7 @@ static ULONG WINAPI media_player_resolver_callback_Release(IMFAsyncCallback *ifa
     return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
 }
 
-static HRESULT WINAPI media_player_resolver_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags,
+static HRESULT WINAPI media_player_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags,
         DWORD *queue)
 {
     return E_NOTIMPL;
@@ -899,9 +1051,10 @@ static HRESULT WINAPI media_player_resolver_callback_GetParameters(IMFAsyncCallb
 static HRESULT WINAPI media_player_resolver_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
 {
     struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
-    struct media_item *item;
+    struct media_event *event;
     IUnknown *object, *state;
     MF_OBJECT_TYPE obj_type;
+    struct media_item *item;
     HRESULT hr;
 
     if (FAILED(IMFAsyncResult_GetState(result, &state)))
@@ -918,8 +1071,23 @@ static HRESULT WINAPI media_player_resolver_callback_Invoke(IMFAsyncCallback *if
     if (FAILED(hr))
         WARN("Failed to set media source, hr %#x.\n", hr);
 
-    /* FIXME: callback notification */
+    if (FAILED(media_event_create(MFP_EVENT_TYPE_MEDIAITEM_CREATED, hr, &player->IMFPMediaPlayer_iface, &event)))
+    {
+        WARN("Failed to create event object.\n");
+        IUnknown_Release(state);
+        return S_OK;
+    }
+
+    if (SUCCEEDED(hr))
+    {
+        event->u.item_created.pMediaItem = &item->IMFPMediaItem_iface;
+        IMFPMediaItem_AddRef(event->u.item_created.pMediaItem);
+    }
+    event->u.item_created.dwUserData = item->user_data;
+
+    media_player_queue_event(player, event);
 
+    IUnknown_Release(&event->IUnknown_iface);
     IUnknown_Release(state);
 
     return S_OK;
@@ -927,13 +1095,53 @@ static HRESULT WINAPI media_player_resolver_callback_Invoke(IMFAsyncCallback *if
 
 static const IMFAsyncCallbackVtbl media_player_resolver_callback_vtbl =
 {
-    media_player_resolver_callback_QueryInterface,
+    media_player_callback_QueryInterface,
     media_player_resolver_callback_AddRef,
     media_player_resolver_callback_Release,
-    media_player_resolver_callback_GetParameters,
+    media_player_callback_GetParameters,
     media_player_resolver_callback_Invoke,
 };
 
+static ULONG WINAPI media_player_events_callback_AddRef(IMFAsyncCallback *iface)
+{
+    struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
+    return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
+}
+
+static ULONG WINAPI media_player_events_callback_Release(IMFAsyncCallback *iface)
+{
+    struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
+    return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
+}
+
+static HRESULT WINAPI media_player_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
+{
+    struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
+    struct media_event *event;
+    IUnknown *state;
+
+    if (FAILED(IMFAsyncResult_GetState(result, &state)))
+        return S_OK;
+
+    event = impl_event_from_IUnknown(state);
+
+    if (player->callback)
+        IMFPMediaPlayerCallback_OnMediaPlayerEvent(player->callback, &event->u.header);
+
+    IUnknown_Release(state);
+
+    return S_OK;
+}
+
+static const IMFAsyncCallbackVtbl media_player_events_callback_vtbl =
+{
+    media_player_callback_QueryInterface,
+    media_player_events_callback_AddRef,
+    media_player_events_callback_Release,
+    media_player_callback_GetParameters,
+    media_player_events_callback_Invoke,
+};
+
 HRESULT WINAPI MFPCreateMediaPlayer(const WCHAR *url, BOOL start_playback, MFP_CREATION_OPTIONS options,
         IMFPMediaPlayerCallback *callback, HWND hwnd, IMFPMediaPlayer **player)
 {
@@ -950,8 +1158,10 @@ HRESULT WINAPI MFPCreateMediaPlayer(const WCHAR *url, BOOL start_playback, MFP_C
     object->IMFPMediaPlayer_iface.lpVtbl = &media_player_vtbl;
     object->IPropertyStore_iface.lpVtbl = &media_player_propstore_vtbl;
     object->resolver_callback.lpVtbl = &media_player_resolver_callback_vtbl;
+    object->events_callback.lpVtbl = &media_player_events_callback_vtbl;
     object->refcount = 1;
     object->callback = callback;
+    object->options = options;
     if (object->callback)
         IMFPMediaPlayerCallback_AddRef(object->callback);
     if (FAILED(hr = CreatePropertyStore(&object->propstore)))
-- 
2.30.2




More information about the wine-devel mailing list