mfplay: Add support for async user callback.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2021-04-06 10:25:31 +03:00 committed by Alexandre Julliard
parent 1f5095f331
commit ef908ef248
1 changed files with 216 additions and 6 deletions

View File

@ -59,10 +59,41 @@ struct media_player
IMFPMediaPlayer IMFPMediaPlayer_iface; IMFPMediaPlayer IMFPMediaPlayer_iface;
IPropertyStore IPropertyStore_iface; IPropertyStore IPropertyStore_iface;
IMFAsyncCallback resolver_callback; IMFAsyncCallback resolver_callback;
IMFAsyncCallback events_callback;
LONG refcount; LONG refcount;
IMFPMediaPlayerCallback *callback; IMFPMediaPlayerCallback *callback;
IPropertyStore *propstore; IPropertyStore *propstore;
IMFSourceResolver *resolver; 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) 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); 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) static struct media_item *impl_from_IMFPMediaItem(IMFPMediaItem *iface)
{ {
return CONTAINING_RECORD(iface, struct media_item, 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) static HRESULT WINAPI media_item_QueryInterface(IMFPMediaItem *iface, REFIID riid, void **obj)
{ {
TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), 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; 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) static HRESULT WINAPI media_player_QueryInterface(IMFPMediaPlayer *iface, REFIID riid, void **obj)
{ {
struct media_player *player = impl_from_IMFPMediaPlayer(iface); struct media_player *player = impl_from_IMFPMediaPlayer(iface);
@ -863,7 +1015,7 @@ static const IPropertyStoreVtbl media_player_propstore_vtbl =
media_player_propstore_Commit, 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) REFIID riid, void **obj)
{ {
if (IsEqualIID(riid, &IID_IMFAsyncCallback) || 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); 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) DWORD *queue)
{ {
return E_NOTIMPL; 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) static HRESULT WINAPI media_player_resolver_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
{ {
struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface); struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
struct media_item *item; struct media_event *event;
IUnknown *object, *state; IUnknown *object, *state;
MF_OBJECT_TYPE obj_type; MF_OBJECT_TYPE obj_type;
struct media_item *item;
HRESULT hr; HRESULT hr;
if (FAILED(IMFAsyncResult_GetState(result, &state))) if (FAILED(IMFAsyncResult_GetState(result, &state)))
@ -918,8 +1071,23 @@ static HRESULT WINAPI media_player_resolver_callback_Invoke(IMFAsyncCallback *if
if (FAILED(hr)) if (FAILED(hr))
WARN("Failed to set media source, hr %#x.\n", 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); IUnknown_Release(state);
return S_OK; 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 = 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_AddRef,
media_player_resolver_callback_Release, media_player_resolver_callback_Release,
media_player_resolver_callback_GetParameters, media_player_callback_GetParameters,
media_player_resolver_callback_Invoke, 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, HRESULT WINAPI MFPCreateMediaPlayer(const WCHAR *url, BOOL start_playback, MFP_CREATION_OPTIONS options,
IMFPMediaPlayerCallback *callback, HWND hwnd, IMFPMediaPlayer **player) 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->IMFPMediaPlayer_iface.lpVtbl = &media_player_vtbl;
object->IPropertyStore_iface.lpVtbl = &media_player_propstore_vtbl; object->IPropertyStore_iface.lpVtbl = &media_player_propstore_vtbl;
object->resolver_callback.lpVtbl = &media_player_resolver_callback_vtbl; object->resolver_callback.lpVtbl = &media_player_resolver_callback_vtbl;
object->events_callback.lpVtbl = &media_player_events_callback_vtbl;
object->refcount = 1; object->refcount = 1;
object->callback = callback; object->callback = callback;
object->options = options;
if (object->callback) if (object->callback)
IMFPMediaPlayerCallback_AddRef(object->callback); IMFPMediaPlayerCallback_AddRef(object->callback);
if (FAILED(hr = CreatePropertyStore(&object->propstore))) if (FAILED(hr = CreatePropertyStore(&object->propstore)))