mfplay: Implement MFP_EVENT_TYPE_PLAYBACK_ENDED event.
[wine.git] / dlls / mfplay / player.c
blobbe51ef2d2e1c260f6112f852994feff565b10c94
1 /*
2 * Copyright 2019 Nikolay Sivov for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
21 #include <stdarg.h>
22 #include <assert.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "mfapi.h"
27 #include "mfplay.h"
28 #include "mferror.h"
30 #include "wine/debug.h"
32 #include "initguid.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
36 DEFINE_GUID(_MF_TOPO_MEDIA_ITEM, 0x6c1bb4df, 0x59ba, 0x4020, 0x85, 0x0c, 0x35, 0x79, 0xa2, 0x7a, 0xe2, 0x51);
38 static const WCHAR eventclassW[] = L"MediaPlayerEventCallbackClass";
40 static LONG startup_refcount;
41 static HINSTANCE mfplay_instance;
43 static void platform_startup(void)
45 if (InterlockedIncrement(&startup_refcount) == 1)
46 MFStartup(MF_VERSION, MFSTARTUP_FULL);
49 static void platform_shutdown(void)
51 if (InterlockedDecrement(&startup_refcount) == 0)
52 MFShutdown();
55 struct media_item
57 IMFPMediaItem IMFPMediaItem_iface;
58 LONG refcount;
59 IMFPMediaPlayer *player;
60 IMFMediaSource *source;
61 IMFPresentationDescriptor *pd;
62 DWORD_PTR user_data;
63 WCHAR *url;
64 IUnknown *object;
67 struct media_player
69 IMFPMediaPlayer IMFPMediaPlayer_iface;
70 IPropertyStore IPropertyStore_iface;
71 IMFAsyncCallback resolver_callback;
72 IMFAsyncCallback events_callback;
73 IMFAsyncCallback session_events_callback;
74 LONG refcount;
75 IMFPMediaPlayerCallback *callback;
76 IPropertyStore *propstore;
77 IMFSourceResolver *resolver;
78 IMFMediaSession *session;
79 IMFPMediaItem *item;
80 MFP_CREATION_OPTIONS options;
81 MFP_MEDIAPLAYER_STATE state;
82 HWND event_window;
83 HWND output_window;
84 CRITICAL_SECTION cs;
87 struct generic_event
89 MFP_EVENT_HEADER header;
90 IMFPMediaItem *item;
93 struct media_event
95 IUnknown IUnknown_iface;
96 LONG refcount;
97 union
99 MFP_EVENT_HEADER header;
100 struct generic_event generic;
101 MFP_PLAY_EVENT play;
102 MFP_PAUSE_EVENT pause;
103 MFP_STOP_EVENT stop;
104 MFP_POSITION_SET_EVENT position_set;
105 MFP_RATE_SET_EVENT rate_set;
106 MFP_MEDIAITEM_CREATED_EVENT item_created;
107 MFP_MEDIAITEM_SET_EVENT item_set;
108 MFP_MEDIAITEM_CLEARED_EVENT item_cleared;
109 MFP_MF_EVENT event;
110 MFP_ERROR_EVENT error;
111 MFP_PLAYBACK_ENDED_EVENT ended;
112 MFP_ACQUIRE_USER_CREDENTIAL_EVENT acquire_creds;
113 } u;
116 static struct media_player *impl_from_IMFPMediaPlayer(IMFPMediaPlayer *iface)
118 return CONTAINING_RECORD(iface, struct media_player, IMFPMediaPlayer_iface);
121 static struct media_player *impl_from_IPropertyStore(IPropertyStore *iface)
123 return CONTAINING_RECORD(iface, struct media_player, IPropertyStore_iface);
126 static struct media_player *impl_from_resolver_IMFAsyncCallback(IMFAsyncCallback *iface)
128 return CONTAINING_RECORD(iface, struct media_player, resolver_callback);
131 static struct media_player *impl_from_events_IMFAsyncCallback(IMFAsyncCallback *iface)
133 return CONTAINING_RECORD(iface, struct media_player, events_callback);
136 static struct media_player *impl_from_session_events_IMFAsyncCallback(IMFAsyncCallback *iface)
138 return CONTAINING_RECORD(iface, struct media_player, session_events_callback);
141 static struct media_item *impl_from_IMFPMediaItem(IMFPMediaItem *iface)
143 return CONTAINING_RECORD(iface, struct media_item, IMFPMediaItem_iface);
146 static struct media_event *impl_event_from_IUnknown(IUnknown *iface)
148 return CONTAINING_RECORD(iface, struct media_event, IUnknown_iface);
151 static HRESULT WINAPI media_event_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
153 if (IsEqualIID(riid, &IID_IUnknown))
155 *obj = iface;
156 IUnknown_AddRef(iface);
157 return S_OK;
160 *obj = NULL;
161 return E_NOINTERFACE;
164 static ULONG WINAPI media_event_AddRef(IUnknown *iface)
166 struct media_event *event = impl_event_from_IUnknown(iface);
167 ULONG refcount = InterlockedIncrement(&event->refcount);
169 TRACE("%p, refcount %u.\n", iface, refcount);
171 return refcount;
174 static ULONG WINAPI media_event_Release(IUnknown *iface)
176 struct media_event *event = impl_event_from_IUnknown(iface);
177 ULONG refcount = InterlockedDecrement(&event->refcount);
179 TRACE("%p, refcount %u.\n", iface, refcount);
181 if (!refcount)
183 if (event->u.header.pMediaPlayer)
184 IMFPMediaPlayer_Release(event->u.header.pMediaPlayer);
185 if (event->u.header.pPropertyStore)
186 IPropertyStore_Release(event->u.header.pPropertyStore);
188 switch (event->u.header.eEventType)
190 /* Most types share same layout. */
191 case MFP_EVENT_TYPE_PLAY:
192 case MFP_EVENT_TYPE_PAUSE:
193 case MFP_EVENT_TYPE_STOP:
194 case MFP_EVENT_TYPE_POSITION_SET:
195 case MFP_EVENT_TYPE_RATE_SET:
196 case MFP_EVENT_TYPE_MEDIAITEM_CREATED:
197 case MFP_EVENT_TYPE_MEDIAITEM_SET:
198 case MFP_EVENT_TYPE_FRAME_STEP:
199 case MFP_EVENT_TYPE_MEDIAITEM_CLEARED:
200 case MFP_EVENT_TYPE_PLAYBACK_ENDED:
201 if (event->u.generic.item)
202 IMFPMediaItem_Release(event->u.generic.item);
203 break;
204 case MFP_EVENT_TYPE_MF:
205 if (event->u.event.pMFMediaEvent)
206 IMFMediaEvent_Release(event->u.event.pMFMediaEvent);
207 if (event->u.event.pMediaItem)
208 IMFPMediaItem_Release(event->u.event.pMediaItem);
209 break;
210 default:
211 FIXME("Unsupported event %u.\n", event->u.header.eEventType);
212 break;
215 free(event);
218 return refcount;
221 static const IUnknownVtbl media_event_vtbl =
223 media_event_QueryInterface,
224 media_event_AddRef,
225 media_event_Release,
228 static HRESULT media_event_create(struct media_player *player, MFP_EVENT_TYPE event_type,
229 HRESULT hr, IMFPMediaItem *item, struct media_event **event)
231 struct media_event *object;
233 if (!(object = calloc(1, sizeof(*object))))
234 return E_OUTOFMEMORY;
236 object->IUnknown_iface.lpVtbl = &media_event_vtbl;
237 object->refcount = 1;
238 object->u.header.eEventType = event_type;
239 object->u.header.hrEvent = hr;
240 object->u.header.pMediaPlayer = &player->IMFPMediaPlayer_iface;
241 IMFPMediaPlayer_AddRef(object->u.header.pMediaPlayer);
242 object->u.header.eState = player->state;
243 switch (event_type)
245 case MFP_EVENT_TYPE_PLAY:
246 case MFP_EVENT_TYPE_PAUSE:
247 case MFP_EVENT_TYPE_STOP:
248 case MFP_EVENT_TYPE_POSITION_SET:
249 case MFP_EVENT_TYPE_RATE_SET:
250 case MFP_EVENT_TYPE_MEDIAITEM_CREATED:
251 case MFP_EVENT_TYPE_MEDIAITEM_SET:
252 case MFP_EVENT_TYPE_FRAME_STEP:
253 case MFP_EVENT_TYPE_MEDIAITEM_CLEARED:
254 case MFP_EVENT_TYPE_PLAYBACK_ENDED:
255 object->u.generic.item = item;
256 if (object->u.generic.item)
257 IMFPMediaItem_AddRef(object->u.generic.item);
258 break;
259 case MFP_EVENT_TYPE_MF:
260 object->u.event.pMediaItem = item;
261 if (object->u.event.pMediaItem)
262 IMFPMediaItem_AddRef(object->u.event.pMediaItem);
263 break;
264 default:
268 /* FIXME: set properties for some events? */
270 *event = object;
272 return S_OK;
275 static LRESULT WINAPI media_player_event_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
277 struct media_event *event = (void *)lparam;
278 struct media_player *player;
280 if (msg == WM_USER)
282 player = impl_from_IMFPMediaPlayer(event->u.header.pMediaPlayer);
283 if (player->callback)
284 IMFPMediaPlayerCallback_OnMediaPlayerEvent(player->callback, &event->u.header);
285 IUnknown_Release(&event->IUnknown_iface);
286 return 0;
289 return DefWindowProcW(hwnd, msg, wparam, lparam);
292 static void media_player_set_state(struct media_player *player, MFP_MEDIAPLAYER_STATE state)
294 if (player->state != MFP_MEDIAPLAYER_STATE_SHUTDOWN)
296 if (state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
297 IMFMediaSession_Shutdown(player->session);
298 player->state = state;
302 static HRESULT WINAPI media_item_QueryInterface(IMFPMediaItem *iface, REFIID riid, void **obj)
304 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
306 if (IsEqualIID(riid, &IID_IMFPMediaItem) ||
307 IsEqualIID(riid, &IID_IUnknown))
309 *obj = iface;
310 IMFPMediaItem_AddRef(iface);
311 return S_OK;
314 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
315 *obj = NULL;
316 return E_NOINTERFACE;
319 static ULONG WINAPI media_item_AddRef(IMFPMediaItem *iface)
321 struct media_item *item = impl_from_IMFPMediaItem(iface);
322 ULONG refcount = InterlockedIncrement(&item->refcount);
324 TRACE("%p, refcount %u.\n", iface, refcount);
326 return refcount;
329 static ULONG WINAPI media_item_Release(IMFPMediaItem *iface)
331 struct media_item *item = impl_from_IMFPMediaItem(iface);
332 ULONG refcount = InterlockedDecrement(&item->refcount);
334 TRACE("%p, refcount %u.\n", iface, refcount);
336 if (!refcount)
338 if (item->player)
339 IMFPMediaPlayer_Release(item->player);
340 if (item->source)
341 IMFMediaSource_Release(item->source);
342 if (item->pd)
343 IMFPresentationDescriptor_Release(item->pd);
344 if (item->object)
345 IUnknown_Release(item->object);
346 free(item->url);
347 free(item);
350 return refcount;
353 static HRESULT WINAPI media_item_GetMediaPlayer(IMFPMediaItem *iface,
354 IMFPMediaPlayer **player)
356 struct media_item *item = impl_from_IMFPMediaItem(iface);
358 TRACE("%p, %p.\n", iface, player);
360 *player = item->player;
361 IMFPMediaPlayer_AddRef(*player);
363 return S_OK;
366 static HRESULT WINAPI media_item_GetURL(IMFPMediaItem *iface, LPWSTR *url)
368 struct media_item *item = impl_from_IMFPMediaItem(iface);
370 TRACE("%p, %p.\n", iface, url);
372 if (!item->url)
373 return MF_E_NOT_FOUND;
375 if (!(*url = CoTaskMemAlloc((wcslen(item->url) + 1) * sizeof(*item->url))))
376 return E_OUTOFMEMORY;
378 wcscpy(*url, item->url);
380 return S_OK;
383 static HRESULT WINAPI media_item_GetObject(IMFPMediaItem *iface, IUnknown **object)
385 struct media_item *item = impl_from_IMFPMediaItem(iface);
387 TRACE("%p, %p.\n", iface, object);
389 if (!item->object)
390 return MF_E_NOT_FOUND;
392 *object = item->object;
393 IUnknown_AddRef(*object);
395 return S_OK;
398 static HRESULT WINAPI media_item_GetUserData(IMFPMediaItem *iface, DWORD_PTR *user_data)
400 struct media_item *item = impl_from_IMFPMediaItem(iface);
402 TRACE("%p, %p.\n", iface, user_data);
404 *user_data = item->user_data;
406 return S_OK;
409 static HRESULT WINAPI media_item_SetUserData(IMFPMediaItem *iface, DWORD_PTR user_data)
411 struct media_item *item = impl_from_IMFPMediaItem(iface);
413 TRACE("%p, %lx.\n", iface, user_data);
415 item->user_data = user_data;
417 return S_OK;
420 static HRESULT WINAPI media_item_GetStartStopPosition(IMFPMediaItem *iface, GUID *start_format,
421 PROPVARIANT *start_position, GUID *stop_format, PROPVARIANT *stop_position)
423 FIXME("%p, %p, %p, %p, %p.\n", iface, start_format, start_position, stop_format, stop_position);
425 return E_NOTIMPL;
428 static HRESULT WINAPI media_item_SetStartStopPosition(IMFPMediaItem *iface, const GUID *start_format,
429 const PROPVARIANT *start_position, const GUID *stop_format, const PROPVARIANT *stop_position)
431 FIXME("%p, %s, %p, %s, %p.\n", iface, debugstr_guid(start_format), start_position,
432 debugstr_guid(stop_format), stop_position);
434 return E_NOTIMPL;
437 static HRESULT WINAPI media_item_HasVideo(IMFPMediaItem *iface, BOOL *has_video, BOOL *selected)
439 FIXME("%p, %p, %p.\n", iface, has_video, selected);
441 return E_NOTIMPL;
444 static HRESULT WINAPI media_item_HasAudio(IMFPMediaItem *iface, BOOL *has_audio, BOOL *selected)
446 FIXME("%p, %p, %p.\n", iface, has_audio, selected);
448 return E_NOTIMPL;
451 static HRESULT WINAPI media_item_IsProtected(IMFPMediaItem *iface, BOOL *protected)
453 struct media_item *item = impl_from_IMFPMediaItem(iface);
455 TRACE("%p, %p.\n", iface, protected);
457 *protected = MFRequireProtectedEnvironment(item->pd) == S_OK;
459 return S_OK;
462 static HRESULT WINAPI media_item_GetDuration(IMFPMediaItem *iface, REFGUID format, PROPVARIANT *value)
464 struct media_item *item = impl_from_IMFPMediaItem(iface);
466 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), value);
468 return IMFPresentationDescriptor_GetItem(item->pd, &MF_PD_DURATION, value);
471 static HRESULT WINAPI media_item_GetNumberOfStreams(IMFPMediaItem *iface, DWORD *count)
473 struct media_item *item = impl_from_IMFPMediaItem(iface);
475 TRACE("%p, %p.\n", iface, count);
477 return IMFPresentationDescriptor_GetStreamDescriptorCount(item->pd, count);
480 static HRESULT WINAPI media_item_GetStreamSelection(IMFPMediaItem *iface, DWORD index, BOOL *selected)
482 struct media_item *item = impl_from_IMFPMediaItem(iface);
483 IMFStreamDescriptor *sd;
484 HRESULT hr;
486 TRACE("%p, %u, %p.\n", iface, index, selected);
488 if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, index, selected, &sd)))
489 IMFStreamDescriptor_Release(sd);
491 return hr;
494 static HRESULT WINAPI media_item_SetStreamSelection(IMFPMediaItem *iface, DWORD index, BOOL select)
496 struct media_item *item = impl_from_IMFPMediaItem(iface);
498 TRACE("%p, %u, %d.\n", iface, index, select);
500 return select ? IMFPresentationDescriptor_SelectStream(item->pd, index) :
501 IMFPresentationDescriptor_DeselectStream(item->pd, index);
504 static HRESULT WINAPI media_item_GetStreamAttribute(IMFPMediaItem *iface, DWORD index, REFGUID key,
505 PROPVARIANT *value)
507 struct media_item *item = impl_from_IMFPMediaItem(iface);
508 IMFStreamDescriptor *sd;
509 BOOL selected;
510 HRESULT hr;
512 TRACE("%p, %u, %s, %p.\n", iface, index, debugstr_guid(key), value);
514 if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, index, &selected, &sd)))
516 hr = IMFStreamDescriptor_GetItem(sd, key, value);
517 IMFStreamDescriptor_Release(sd);
520 return hr;
523 static HRESULT WINAPI media_item_GetPresentationAttribute(IMFPMediaItem *iface, REFGUID key,
524 PROPVARIANT *value)
526 struct media_item *item = impl_from_IMFPMediaItem(iface);
528 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
530 return IMFPresentationDescriptor_GetItem(item->pd, key, value);
533 static HRESULT WINAPI media_item_GetCharacteristics(IMFPMediaItem *iface, MFP_MEDIAITEM_CHARACTERISTICS *flags)
535 struct media_item *item = impl_from_IMFPMediaItem(iface);
536 HRESULT hr;
538 TRACE("%p, %p.\n", iface, flags);
540 *flags = 0;
542 if (SUCCEEDED(hr = IMFMediaSource_GetCharacteristics(item->source, flags)))
544 *flags &= (MFP_MEDIAITEM_IS_LIVE | MFP_MEDIAITEM_CAN_SEEK |
545 MFP_MEDIAITEM_CAN_PAUSE | MFP_MEDIAITEM_HAS_SLOW_SEEK);
548 return hr;
551 static HRESULT WINAPI media_item_SetStreamSink(IMFPMediaItem *iface, DWORD index, IUnknown *sink)
553 FIXME("%p, %u, %p.\n", iface, index, sink);
555 return E_NOTIMPL;
558 static HRESULT WINAPI media_item_GetMetadata(IMFPMediaItem *iface, IPropertyStore **metadata)
560 struct media_item *item = impl_from_IMFPMediaItem(iface);
562 TRACE("%p, %p.\n", iface, metadata);
564 return MFGetService((IUnknown *)item->source, &MF_PROPERTY_HANDLER_SERVICE,
565 &IID_IPropertyStore, (void **)&metadata);
568 static const IMFPMediaItemVtbl media_item_vtbl =
570 media_item_QueryInterface,
571 media_item_AddRef,
572 media_item_Release,
573 media_item_GetMediaPlayer,
574 media_item_GetURL,
575 media_item_GetObject,
576 media_item_GetUserData,
577 media_item_SetUserData,
578 media_item_GetStartStopPosition,
579 media_item_SetStartStopPosition,
580 media_item_HasVideo,
581 media_item_HasAudio,
582 media_item_IsProtected,
583 media_item_GetDuration,
584 media_item_GetNumberOfStreams,
585 media_item_GetStreamSelection,
586 media_item_SetStreamSelection,
587 media_item_GetStreamAttribute,
588 media_item_GetPresentationAttribute,
589 media_item_GetCharacteristics,
590 media_item_SetStreamSink,
591 media_item_GetMetadata,
594 static struct media_item *unsafe_impl_from_IMFPMediaItem(IMFPMediaItem *iface)
596 if (!iface)
597 return NULL;
598 assert(iface->lpVtbl == (IMFPMediaItemVtbl *)&media_item_vtbl);
599 return CONTAINING_RECORD(iface, struct media_item, IMFPMediaItem_iface);
602 static HRESULT create_media_item(IMFPMediaPlayer *player, DWORD_PTR user_data, struct media_item **item)
604 struct media_item *object;
606 if (!(object = calloc(1, sizeof(*object))))
607 return E_OUTOFMEMORY;
609 object->IMFPMediaItem_iface.lpVtbl = &media_item_vtbl;
610 object->refcount = 1;
611 object->user_data = user_data;
612 object->player = player;
613 IMFPMediaPlayer_AddRef(object->player);
615 *item = object;
617 return S_OK;
620 static HRESULT media_item_set_source(struct media_item *item, IUnknown *object)
622 IMFPresentationDescriptor *pd;
623 IMFMediaSource *source;
624 HRESULT hr;
626 if (FAILED(hr = IUnknown_QueryInterface(object, &IID_IMFMediaSource, (void **)&source)))
627 return hr;
629 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd)))
631 WARN("Failed to get presentation descriptor, hr %#x.\n", hr);
632 IMFMediaSource_Release(source);
633 return hr;
636 item->source = source;
637 item->pd = pd;
639 return hr;
642 static void media_player_queue_event(struct media_player *player, struct media_event *event)
644 if (player->options & MFP_OPTION_FREE_THREADED_CALLBACK)
646 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, &player->events_callback, &event->IUnknown_iface);
648 else
650 IUnknown_AddRef(&event->IUnknown_iface);
651 PostMessageW(player->event_window, WM_USER, 0, (LPARAM)event);
655 static HRESULT WINAPI media_player_QueryInterface(IMFPMediaPlayer *iface, REFIID riid, void **obj)
657 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
659 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
661 if (IsEqualIID(riid, &IID_IMFPMediaPlayer) ||
662 IsEqualIID(riid, &IID_IUnknown))
664 *obj = &player->IMFPMediaPlayer_iface;
666 else if (IsEqualIID(riid, &IID_IPropertyStore))
668 *obj = &player->IPropertyStore_iface;
670 else
672 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
673 *obj = NULL;
675 return E_NOINTERFACE;
678 IUnknown_AddRef((IUnknown *)*obj);
679 return S_OK;
682 static ULONG WINAPI media_player_AddRef(IMFPMediaPlayer *iface)
684 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
685 ULONG refcount = InterlockedIncrement(&player->refcount);
687 TRACE("%p, refcount %u.\n", iface, refcount);
689 return refcount;
692 static ULONG WINAPI media_player_Release(IMFPMediaPlayer *iface)
694 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
695 ULONG refcount = InterlockedDecrement(&player->refcount);
697 TRACE("%p, refcount %u.\n", iface, refcount);
699 if (!refcount)
701 if (player->callback)
702 IMFPMediaPlayerCallback_Release(player->callback);
703 if (player->propstore)
704 IPropertyStore_Release(player->propstore);
705 if (player->resolver)
706 IMFSourceResolver_Release(player->resolver);
707 if (player->session)
708 IMFMediaSession_Release(player->session);
709 DestroyWindow(player->event_window);
710 DeleteCriticalSection(&player->cs);
711 free(player);
713 platform_shutdown();
716 return refcount;
719 static HRESULT WINAPI media_player_Play(IMFPMediaPlayer *iface)
721 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
722 PROPVARIANT pos;
724 TRACE("%p.\n", iface);
726 pos.vt = VT_EMPTY;
727 return IMFMediaSession_Start(player->session, &GUID_NULL, &pos);
730 static HRESULT WINAPI media_player_Pause(IMFPMediaPlayer *iface)
732 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
734 TRACE("%p.\n", iface);
736 return IMFMediaSession_Pause(player->session);
739 static HRESULT WINAPI media_player_Stop(IMFPMediaPlayer *iface)
741 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
743 TRACE("%p.\n", iface);
745 return IMFMediaSession_Stop(player->session);
748 static HRESULT WINAPI media_player_FrameStep(IMFPMediaPlayer *iface)
750 FIXME("%p.\n", iface);
752 return E_NOTIMPL;
755 static HRESULT WINAPI media_player_SetPosition(IMFPMediaPlayer *iface, REFGUID postype, const PROPVARIANT *position)
757 FIXME("%p, %s, %p.\n", iface, debugstr_guid(postype), position);
759 return E_NOTIMPL;
762 static HRESULT WINAPI media_player_GetPosition(IMFPMediaPlayer *iface, REFGUID postype, PROPVARIANT *position)
764 FIXME("%p, %s, %p.\n", iface, debugstr_guid(postype), position);
766 return E_NOTIMPL;
769 static HRESULT WINAPI media_player_GetDuration(IMFPMediaPlayer *iface, REFGUID postype, PROPVARIANT *position)
771 FIXME("%p, %s, %p.\n", iface, debugstr_guid(postype), position);
773 return E_NOTIMPL;
776 static HRESULT WINAPI media_player_SetRate(IMFPMediaPlayer *iface, float rate)
778 FIXME("%p, %f.\n", iface, rate);
780 return E_NOTIMPL;
783 static HRESULT WINAPI media_player_GetRate(IMFPMediaPlayer *iface, float *rate)
785 FIXME("%p, %p.\n", iface, rate);
787 return E_NOTIMPL;
790 static HRESULT WINAPI media_player_GetSupportedRates(IMFPMediaPlayer *iface, BOOL forward,
791 float *slowest_rate, float *fastest_rate)
793 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
794 IMFRateSupport *rs;
795 HRESULT hr;
797 TRACE("%p, %d, %p, %p.\n", iface, forward, slowest_rate, fastest_rate);
799 if (SUCCEEDED(hr = MFGetService((IUnknown *)player->session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rs)))
801 if (SUCCEEDED(hr = IMFRateSupport_GetSlowestRate(rs, forward ? MFRATE_FORWARD : MFRATE_REVERSE, FALSE, slowest_rate)))
802 hr = IMFRateSupport_GetFastestRate(rs, forward ? MFRATE_FORWARD : MFRATE_REVERSE, FALSE, fastest_rate);
803 IMFRateSupport_Release(rs);
806 return hr;
809 static HRESULT WINAPI media_player_GetState(IMFPMediaPlayer *iface, MFP_MEDIAPLAYER_STATE *state)
811 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
813 TRACE("%p, %p.\n", iface, state);
815 *state = player->state;
817 return S_OK;
820 static HRESULT media_player_create_item_from_url(struct media_player *player,
821 const WCHAR *url, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **ret)
823 struct media_item *item;
824 MF_OBJECT_TYPE obj_type;
825 IUnknown *object;
826 HRESULT hr;
828 *ret = NULL;
830 if (FAILED(hr = create_media_item(&player->IMFPMediaPlayer_iface, user_data, &item)))
831 return hr;
833 if (url && !(item->url = wcsdup(url)))
835 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
836 return E_OUTOFMEMORY;
839 if (sync)
841 if (SUCCEEDED(hr = IMFSourceResolver_CreateObjectFromURL(player->resolver, url, MF_RESOLUTION_MEDIASOURCE,
842 player->propstore, &obj_type, &object)))
844 hr = media_item_set_source(item, object);
845 IUnknown_Release(object);
848 if (SUCCEEDED(hr))
850 *ret = &item->IMFPMediaItem_iface;
851 IMFPMediaItem_AddRef(*ret);
854 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
856 return hr;
858 else
860 hr = IMFSourceResolver_BeginCreateObjectFromURL(player->resolver, url, MF_RESOLUTION_MEDIASOURCE,
861 player->propstore, NULL, &player->resolver_callback, (IUnknown *)&item->IMFPMediaItem_iface);
863 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
866 return hr;
869 static HRESULT WINAPI media_player_CreateMediaItemFromURL(IMFPMediaPlayer *iface,
870 const WCHAR *url, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **item)
872 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
873 HRESULT hr;
875 TRACE("%p, %s, %d, %lx, %p.\n", iface, debugstr_w(url), sync, user_data, item);
877 EnterCriticalSection(&player->cs);
878 if (player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
879 hr = MF_E_SHUTDOWN;
880 else
881 hr = media_player_create_item_from_url(player, url, sync, user_data, item);
882 LeaveCriticalSection(&player->cs);
884 return hr;
887 static HRESULT media_player_create_item_from_object(struct media_player *player,
888 IUnknown *object, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **ret)
890 struct media_item *item;
891 MF_OBJECT_TYPE obj_type;
892 HRESULT hr;
893 IMFByteStream *stream = NULL;
894 IMFMediaSource *source = NULL;
896 *ret = NULL;
898 if (FAILED(hr = create_media_item(&player->IMFPMediaPlayer_iface, user_data, &item)))
899 return hr;
901 item->object = object;
902 IUnknown_AddRef(item->object);
904 if (FAILED(IUnknown_QueryInterface(object, &IID_IMFMediaSource, (void **)&source)))
905 IUnknown_QueryInterface(object, &IID_IMFByteStream, (void **)&stream);
907 if (!source && !stream)
909 WARN("Unsupported object type.\n");
910 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
911 return E_UNEXPECTED;
914 if (sync)
916 if (stream)
917 hr = IMFSourceResolver_CreateObjectFromByteStream(player->resolver, stream, NULL,
918 MF_RESOLUTION_MEDIASOURCE, player->propstore, &obj_type, &object);
919 else
920 IUnknown_AddRef(object);
922 if (SUCCEEDED(hr))
923 hr = media_item_set_source(item, object);
925 IUnknown_Release(object);
927 if (SUCCEEDED(hr))
929 *ret = &item->IMFPMediaItem_iface;
930 IMFPMediaItem_AddRef(*ret);
933 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
935 else
937 if (stream)
939 hr = IMFSourceResolver_BeginCreateObjectFromByteStream(player->resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE,
940 player->propstore, NULL, &player->resolver_callback, (IUnknown *)&item->IMFPMediaItem_iface);
942 else
944 /* Resolver callback will check again if item's object is a source. */
945 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, &player->resolver_callback,
946 (IUnknown *)&item->IMFPMediaItem_iface);
949 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
952 if (source)
953 IMFMediaSource_Release(source);
954 if (stream)
955 IMFByteStream_Release(stream);
957 return hr;
960 static HRESULT WINAPI media_player_CreateMediaItemFromObject(IMFPMediaPlayer *iface,
961 IUnknown *object, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **item)
963 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
964 HRESULT hr;
966 TRACE("%p, %p, %d, %lx, %p.\n", iface, object, sync, user_data, item);
968 EnterCriticalSection(&player->cs);
969 if (player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
970 hr = MF_E_SHUTDOWN;
971 else
972 hr = media_player_create_item_from_object(player, object, sync, user_data, item);
973 LeaveCriticalSection(&player->cs);
975 return hr;
978 static HRESULT media_item_get_stream_type(IMFStreamDescriptor *sd, GUID *major)
980 IMFMediaTypeHandler *handler;
981 HRESULT hr;
983 if (SUCCEEDED(hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler)))
985 hr = IMFMediaTypeHandler_GetMajorType(handler, major);
986 IMFMediaTypeHandler_Release(handler);
989 return hr;
992 static HRESULT media_item_create_topology(struct media_player *player, struct media_item *item, IMFTopology **out)
994 IMFTopologyNode *src_node, *sink_node;
995 IMFActivate *sar_activate;
996 IMFStreamDescriptor *sd;
997 IMFTopology *topology;
998 unsigned int idx;
999 BOOL selected;
1000 HRESULT hr;
1001 GUID major;
1003 if (FAILED(hr = MFCreateTopology(&topology)))
1004 return hr;
1006 /* FIXME: handle user sinks */
1008 /* Use first stream if none selected. */
1009 if (player->output_window)
1011 FIXME("Video streams are not handled.\n");
1014 /* Set up audio branches for all selected streams. */
1016 idx = 0;
1017 while (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, idx++, &selected, &sd)))
1019 if (selected && SUCCEEDED(media_item_get_stream_type(sd, &major)) && IsEqualGUID(&major, &MFMediaType_Audio))
1021 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &src_node)))
1023 IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_SOURCE, (IUnknown *)item->source);
1024 IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)item->pd);
1025 IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd);
1027 IMFTopology_AddNode(topology, src_node);
1030 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &sink_node)))
1032 if (SUCCEEDED(MFCreateAudioRendererActivate(&sar_activate)))
1034 IMFTopologyNode_SetObject(sink_node, (IUnknown *)sar_activate);
1035 IMFActivate_Release(sar_activate);
1038 IMFTopology_AddNode(topology, sink_node);
1041 if (src_node && sink_node)
1042 IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0);
1044 if (src_node)
1045 IMFTopologyNode_Release(src_node);
1046 if (sink_node)
1047 IMFTopologyNode_Release(sink_node);
1050 IMFStreamDescriptor_Release(sd);
1053 *out = topology;
1055 return S_OK;
1058 static HRESULT WINAPI media_player_SetMediaItem(IMFPMediaPlayer *iface, IMFPMediaItem *item_iface)
1060 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1061 struct media_item *item = unsafe_impl_from_IMFPMediaItem(item_iface);
1062 IMFTopology *topology;
1063 HRESULT hr;
1065 TRACE("%p, %p.\n", iface, item_iface);
1067 if (item->player != iface)
1068 return E_INVALIDARG;
1070 if (FAILED(hr = media_item_create_topology(player, item, &topology)))
1071 return hr;
1073 IMFTopology_SetUnknown(topology, &_MF_TOPO_MEDIA_ITEM, (IUnknown *)item_iface);
1074 hr = IMFMediaSession_SetTopology(player->session, MFSESSION_SETTOPOLOGY_IMMEDIATE, topology);
1075 IMFTopology_Release(topology);
1077 return hr;
1080 static HRESULT WINAPI media_player_ClearMediaItem(IMFPMediaPlayer *iface)
1082 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1084 TRACE("%p.\n", iface);
1086 return IMFMediaSession_SetTopology(player->session, MFSESSION_SETTOPOLOGY_CLEAR_CURRENT, NULL);
1089 static HRESULT WINAPI media_player_GetMediaItem(IMFPMediaPlayer *iface, IMFPMediaItem **item)
1091 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1092 HRESULT hr = S_OK;
1094 TRACE("%p, %p.\n", iface, item);
1096 if (!item)
1097 return E_POINTER;
1099 EnterCriticalSection(&player->cs);
1100 if (player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
1101 hr = MF_E_SHUTDOWN;
1102 else if (!player->item)
1103 hr = MF_E_NOT_FOUND;
1104 else
1106 *item = player->item;
1107 IMFPMediaItem_AddRef(player->item);
1109 LeaveCriticalSection(&player->cs);
1111 return hr;
1114 static HRESULT WINAPI media_player_GetVolume(IMFPMediaPlayer *iface, float *volume)
1116 FIXME("%p, %p.\n", iface, volume);
1118 return E_NOTIMPL;
1121 static HRESULT WINAPI media_player_SetVolume(IMFPMediaPlayer *iface, float volume)
1123 FIXME("%p, %.8e.\n", iface, volume);
1125 return E_NOTIMPL;
1128 static HRESULT WINAPI media_player_GetBalance(IMFPMediaPlayer *iface, float *balance)
1130 FIXME("%p, %p.\n", iface, balance);
1132 return E_NOTIMPL;
1135 static HRESULT WINAPI media_player_SetBalance(IMFPMediaPlayer *iface, float balance)
1137 FIXME("%p, %.8e.\n", iface, balance);
1139 return E_NOTIMPL;
1142 static HRESULT WINAPI media_player_GetMute(IMFPMediaPlayer *iface, BOOL *mute)
1144 FIXME("%p, %p.\n", iface, mute);
1146 return E_NOTIMPL;
1149 static HRESULT WINAPI media_player_SetMute(IMFPMediaPlayer *iface, BOOL mute)
1151 FIXME("%p, %d.\n", iface, mute);
1153 return E_NOTIMPL;
1156 static HRESULT WINAPI media_player_GetNativeVideoSize(IMFPMediaPlayer *iface,
1157 SIZE *video, SIZE *arvideo)
1159 FIXME("%p, %p, %p.\n", iface, video, arvideo);
1161 return E_NOTIMPL;
1164 static HRESULT WINAPI media_player_GetIdealVideoSize(IMFPMediaPlayer *iface,
1165 SIZE *min_size, SIZE *max_size)
1167 FIXME("%p, %p, %p.\n", iface, min_size, max_size);
1169 return E_NOTIMPL;
1172 static HRESULT WINAPI media_player_SetVideoSourceRect(IMFPMediaPlayer *iface,
1173 MFVideoNormalizedRect const *rect)
1175 FIXME("%p, %p.\n", iface, rect);
1177 return E_NOTIMPL;
1180 static HRESULT WINAPI media_player_GetVideoSourceRect(IMFPMediaPlayer *iface,
1181 MFVideoNormalizedRect *rect)
1183 FIXME("%p, %p.\n", iface, rect);
1185 return E_NOTIMPL;
1188 static HRESULT WINAPI media_player_SetAspectRatioMode(IMFPMediaPlayer *iface, DWORD mode)
1190 FIXME("%p, %u.\n", iface, mode);
1192 return E_NOTIMPL;
1195 static HRESULT WINAPI media_player_GetAspectRatioMode(IMFPMediaPlayer *iface,
1196 DWORD *mode)
1198 FIXME("%p, %p.\n", iface, mode);
1200 return E_NOTIMPL;
1203 static HRESULT WINAPI media_player_GetVideoWindow(IMFPMediaPlayer *iface, HWND *window)
1205 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1207 TRACE("%p, %p.\n", iface, window);
1209 *window = player->output_window;
1211 return S_OK;
1214 static HRESULT WINAPI media_player_UpdateVideo(IMFPMediaPlayer *iface)
1216 FIXME("%p.\n", iface);
1218 return E_NOTIMPL;
1221 static HRESULT WINAPI media_player_SetBorderColor(IMFPMediaPlayer *iface, COLORREF color)
1223 FIXME("%p, %#x.\n", iface, color);
1225 return E_NOTIMPL;
1228 static HRESULT WINAPI media_player_GetBorderColor(IMFPMediaPlayer *iface, COLORREF *color)
1230 FIXME("%p, %p.\n", iface, color);
1232 return E_NOTIMPL;
1235 static HRESULT WINAPI media_player_InsertEffect(IMFPMediaPlayer *iface, IUnknown *effect,
1236 BOOL optional)
1238 FIXME("%p, %p, %d.\n", iface, effect, optional);
1240 return E_NOTIMPL;
1243 static HRESULT WINAPI media_player_RemoveEffect(IMFPMediaPlayer *iface, IUnknown *effect)
1245 FIXME("%p, %p.\n", iface, effect);
1247 return E_NOTIMPL;
1250 static HRESULT WINAPI media_player_RemoveAllEffects(IMFPMediaPlayer *iface)
1252 FIXME("%p.\n", iface);
1254 return E_NOTIMPL;
1257 static HRESULT WINAPI media_player_Shutdown(IMFPMediaPlayer *iface)
1259 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1261 TRACE("%p.\n", iface);
1263 EnterCriticalSection(&player->cs);
1264 media_player_set_state(player, MFP_MEDIAPLAYER_STATE_SHUTDOWN);
1265 if (player->item)
1267 IMFPMediaItem_Release(player->item);
1268 player->item = NULL;
1270 LeaveCriticalSection(&player->cs);
1272 return S_OK;
1275 static const IMFPMediaPlayerVtbl media_player_vtbl =
1277 media_player_QueryInterface,
1278 media_player_AddRef,
1279 media_player_Release,
1280 media_player_Play,
1281 media_player_Pause,
1282 media_player_Stop,
1283 media_player_FrameStep,
1284 media_player_SetPosition,
1285 media_player_GetPosition,
1286 media_player_GetDuration,
1287 media_player_SetRate,
1288 media_player_GetRate,
1289 media_player_GetSupportedRates,
1290 media_player_GetState,
1291 media_player_CreateMediaItemFromURL,
1292 media_player_CreateMediaItemFromObject,
1293 media_player_SetMediaItem,
1294 media_player_ClearMediaItem,
1295 media_player_GetMediaItem,
1296 media_player_GetVolume,
1297 media_player_SetVolume,
1298 media_player_GetBalance,
1299 media_player_SetBalance,
1300 media_player_GetMute,
1301 media_player_SetMute,
1302 media_player_GetNativeVideoSize,
1303 media_player_GetIdealVideoSize,
1304 media_player_SetVideoSourceRect,
1305 media_player_GetVideoSourceRect,
1306 media_player_SetAspectRatioMode,
1307 media_player_GetAspectRatioMode,
1308 media_player_GetVideoWindow,
1309 media_player_UpdateVideo,
1310 media_player_SetBorderColor,
1311 media_player_GetBorderColor,
1312 media_player_InsertEffect,
1313 media_player_RemoveEffect,
1314 media_player_RemoveAllEffects,
1315 media_player_Shutdown,
1318 static HRESULT WINAPI media_player_propstore_QueryInterface(IPropertyStore *iface,
1319 REFIID riid, void **obj)
1321 struct media_player *player = impl_from_IPropertyStore(iface);
1322 return IMFPMediaPlayer_QueryInterface(&player->IMFPMediaPlayer_iface, riid, obj);
1325 static ULONG WINAPI media_player_propstore_AddRef(IPropertyStore *iface)
1327 struct media_player *player = impl_from_IPropertyStore(iface);
1328 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1331 static ULONG WINAPI media_player_propstore_Release(IPropertyStore *iface)
1333 struct media_player *player = impl_from_IPropertyStore(iface);
1334 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1337 static HRESULT WINAPI media_player_propstore_GetCount(IPropertyStore *iface, DWORD *count)
1339 struct media_player *player = impl_from_IPropertyStore(iface);
1341 TRACE("%p, %p.\n", iface, count);
1343 return IPropertyStore_GetCount(player->propstore, count);
1346 static HRESULT WINAPI media_player_propstore_GetAt(IPropertyStore *iface, DWORD prop, PROPERTYKEY *key)
1348 struct media_player *player = impl_from_IPropertyStore(iface);
1350 TRACE("%p, %u, %p.\n", iface, prop, key);
1352 return IPropertyStore_GetAt(player->propstore, prop, key);
1355 static HRESULT WINAPI media_player_propstore_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *value)
1357 struct media_player *player = impl_from_IPropertyStore(iface);
1359 TRACE("%p, %p, %p.\n", iface, key, value);
1361 return IPropertyStore_GetValue(player->propstore, key, value);
1364 static HRESULT WINAPI media_player_propstore_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT value)
1366 struct media_player *player = impl_from_IPropertyStore(iface);
1368 TRACE("%p, %p, %p.\n", iface, key, value);
1370 return IPropertyStore_SetValue(player->propstore, key, value);
1373 static HRESULT WINAPI media_player_propstore_Commit(IPropertyStore *iface)
1375 struct media_player *player = impl_from_IPropertyStore(iface);
1377 TRACE("%p.\n", iface);
1379 return IPropertyStore_Commit(player->propstore);
1382 static const IPropertyStoreVtbl media_player_propstore_vtbl =
1384 media_player_propstore_QueryInterface,
1385 media_player_propstore_AddRef,
1386 media_player_propstore_Release,
1387 media_player_propstore_GetCount,
1388 media_player_propstore_GetAt,
1389 media_player_propstore_GetValue,
1390 media_player_propstore_SetValue,
1391 media_player_propstore_Commit,
1394 static HRESULT WINAPI media_player_callback_QueryInterface(IMFAsyncCallback *iface,
1395 REFIID riid, void **obj)
1397 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
1398 IsEqualIID(riid, &IID_IUnknown))
1400 *obj = iface;
1401 IMFAsyncCallback_AddRef(iface);
1402 return S_OK;
1405 *obj = NULL;
1406 return E_NOINTERFACE;
1409 static ULONG WINAPI media_player_resolver_callback_AddRef(IMFAsyncCallback *iface)
1411 struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
1412 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1415 static ULONG WINAPI media_player_resolver_callback_Release(IMFAsyncCallback *iface)
1417 struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
1418 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1421 static HRESULT WINAPI media_player_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags,
1422 DWORD *queue)
1424 return E_NOTIMPL;
1427 static HRESULT WINAPI media_player_resolver_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1429 struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
1430 struct media_event *event;
1431 IUnknown *object, *state;
1432 MF_OBJECT_TYPE obj_type;
1433 struct media_item *item;
1434 HRESULT hr;
1436 if (FAILED(IMFAsyncResult_GetState(result, &state)))
1437 return S_OK;
1439 item = impl_from_IMFPMediaItem((IMFPMediaItem *)state);
1441 if (item->object)
1443 if (FAILED(hr = IUnknown_QueryInterface(item->object, &IID_IMFMediaSource, (void **)&object)))
1444 hr = IMFSourceResolver_EndCreateObjectFromByteStream(player->resolver, result, &obj_type, &object);
1446 else
1447 hr = IMFSourceResolver_EndCreateObjectFromURL(player->resolver, result, &obj_type, &object);
1449 if (SUCCEEDED(hr))
1451 hr = media_item_set_source(item, object);
1452 IUnknown_Release(object);
1455 if (FAILED(hr))
1456 WARN("Failed to set media source, hr %#x.\n", hr);
1458 if (FAILED(media_event_create(player, MFP_EVENT_TYPE_MEDIAITEM_CREATED, hr,
1459 &item->IMFPMediaItem_iface, &event)))
1461 WARN("Failed to create event object.\n");
1462 IUnknown_Release(state);
1463 return S_OK;
1465 event->u.item_created.dwUserData = item->user_data;
1467 media_player_queue_event(player, event);
1469 IUnknown_Release(&event->IUnknown_iface);
1470 IUnknown_Release(state);
1472 return S_OK;
1475 static const IMFAsyncCallbackVtbl media_player_resolver_callback_vtbl =
1477 media_player_callback_QueryInterface,
1478 media_player_resolver_callback_AddRef,
1479 media_player_resolver_callback_Release,
1480 media_player_callback_GetParameters,
1481 media_player_resolver_callback_Invoke,
1484 static ULONG WINAPI media_player_events_callback_AddRef(IMFAsyncCallback *iface)
1486 struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
1487 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1490 static ULONG WINAPI media_player_events_callback_Release(IMFAsyncCallback *iface)
1492 struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
1493 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1496 static HRESULT WINAPI media_player_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1498 struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
1499 struct media_event *event;
1500 IUnknown *state;
1502 if (FAILED(IMFAsyncResult_GetState(result, &state)))
1503 return S_OK;
1505 event = impl_event_from_IUnknown(state);
1507 if (player->callback)
1508 IMFPMediaPlayerCallback_OnMediaPlayerEvent(player->callback, &event->u.header);
1510 IUnknown_Release(state);
1512 return S_OK;
1515 static const IMFAsyncCallbackVtbl media_player_events_callback_vtbl =
1517 media_player_callback_QueryInterface,
1518 media_player_events_callback_AddRef,
1519 media_player_events_callback_Release,
1520 media_player_callback_GetParameters,
1521 media_player_events_callback_Invoke,
1524 static ULONG WINAPI media_player_session_events_callback_AddRef(IMFAsyncCallback *iface)
1526 struct media_player *player = impl_from_session_events_IMFAsyncCallback(iface);
1527 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1530 static ULONG WINAPI media_player_session_events_callback_Release(IMFAsyncCallback *iface)
1532 struct media_player *player = impl_from_session_events_IMFAsyncCallback(iface);
1533 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1536 static void media_player_change_state(struct media_player *player, MFP_MEDIAPLAYER_STATE state,
1537 HRESULT event_status, struct media_event **event)
1539 MFP_EVENT_TYPE event_type;
1541 EnterCriticalSection(&player->cs);
1543 if (state == MFP_MEDIAPLAYER_STATE_PLAYING)
1544 event_type = MFP_EVENT_TYPE_PLAY;
1545 else if (state == MFP_MEDIAPLAYER_STATE_PAUSED)
1546 event_type = MFP_EVENT_TYPE_PAUSE;
1547 else
1548 event_type = MFP_EVENT_TYPE_STOP;
1550 media_player_set_state(player, state);
1551 media_event_create(player, event_type, event_status, player->item, event);
1553 LeaveCriticalSection(&player->cs);
1556 static void media_player_set_item(struct media_player *player, IMFTopology *topology, HRESULT event_status,
1557 struct media_event **event)
1559 IMFPMediaItem *item;
1561 if (FAILED(IMFTopology_GetUnknown(topology, &_MF_TOPO_MEDIA_ITEM, &IID_IMFPMediaItem, (void **)&item)))
1562 return;
1564 EnterCriticalSection(&player->cs);
1566 if (player->item)
1567 IMFPMediaItem_Release(player->item);
1568 player->item = item;
1569 IMFPMediaItem_AddRef(player->item);
1571 media_event_create(player, MFP_EVENT_TYPE_MEDIAITEM_SET, event_status, item, event);
1573 LeaveCriticalSection(&player->cs);
1575 IMFPMediaItem_Release(item);
1578 static void media_player_clear_item(struct media_player *player, HRESULT event_status,
1579 struct media_event **event)
1581 IMFPMediaItem *item;
1583 EnterCriticalSection(&player->cs);
1585 item = player->item;
1586 player->item = NULL;
1588 media_event_create(player, MFP_EVENT_TYPE_MEDIAITEM_SET, event_status, item, event);
1590 LeaveCriticalSection(&player->cs);
1593 static void media_player_create_forward_event(struct media_player *player, HRESULT event_status, IMFMediaEvent *session_event,
1594 struct media_event **event)
1596 EnterCriticalSection(&player->cs);
1598 if (SUCCEEDED(media_event_create(player, MFP_EVENT_TYPE_MF, event_status, player->item, event)))
1600 IMFMediaEvent_GetType(session_event, &(*event)->u.event.MFEventType);
1601 (*event)->u.event.pMFMediaEvent = session_event;
1602 IMFMediaEvent_AddRef((*event)->u.event.pMFMediaEvent);
1605 LeaveCriticalSection(&player->cs);
1608 static void media_player_create_playback_ended_event(struct media_player *player, HRESULT event_status,
1609 struct media_event **event)
1611 EnterCriticalSection(&player->cs);
1613 if (SUCCEEDED(media_event_create(player, MFP_EVENT_TYPE_PLAYBACK_ENDED, event_status, player->item, event)))
1615 if (player->item)
1616 IMFPMediaItem_Release(player->item);
1617 player->item = NULL;
1620 LeaveCriticalSection(&player->cs);
1623 static HRESULT WINAPI media_player_session_events_callback_Invoke(IMFAsyncCallback *iface,
1624 IMFAsyncResult *result)
1626 struct media_player *player = impl_from_session_events_IMFAsyncCallback(iface);
1627 MediaEventType session_event_type = MEUnknown;
1628 struct media_event *event = NULL;
1629 IMFMediaEvent *session_event;
1630 MFP_MEDIAPLAYER_STATE state;
1631 HRESULT hr, event_status;
1632 IMFPMediaItem *item = NULL;
1633 IMFTopology *topology;
1634 unsigned int status;
1635 PROPVARIANT value;
1637 if (FAILED(hr = IMFMediaSession_EndGetEvent(player->session, result, &session_event)))
1638 return S_OK;
1640 IMFMediaEvent_GetType(session_event, &session_event_type);
1641 IMFMediaEvent_GetStatus(session_event, &event_status);
1643 switch (session_event_type)
1645 case MESessionStarted:
1646 case MESessionStopped:
1647 case MESessionPaused:
1649 if (session_event_type == MESessionStarted)
1650 state = MFP_MEDIAPLAYER_STATE_PLAYING;
1651 else if (session_event_type == MESessionPaused)
1652 state = MFP_MEDIAPLAYER_STATE_PAUSED;
1653 else
1654 state = MFP_MEDIAPLAYER_STATE_STOPPED;
1656 media_player_change_state(player, state, event_status, &event);
1658 break;
1660 case MESessionTopologySet:
1662 value.vt = VT_EMPTY;
1663 if (SUCCEEDED(IMFMediaEvent_GetValue(session_event, &value)))
1665 if (value.vt == VT_EMPTY)
1667 media_player_clear_item(player, event_status, &event);
1669 else if (value.vt == VT_UNKNOWN && value.punkVal &&
1670 SUCCEEDED(IUnknown_QueryInterface(value.punkVal, &IID_IMFTopology, (void **)&topology)))
1672 media_player_set_item(player, topology, event_status, &event);
1673 IMFTopology_Release(topology);
1675 PropVariantClear(&value);
1678 break;
1680 case MESessionTopologyStatus:
1682 if (SUCCEEDED(IMFMediaEvent_GetUINT32(session_event, &MF_EVENT_TOPOLOGY_STATUS, &status)) &&
1683 status == MF_TOPOSTATUS_ENDED)
1685 media_player_create_playback_ended_event(player, event_status, &event);
1688 break;
1690 case MEBufferingStarted:
1691 case MEBufferingStopped:
1692 case MEExtendedType:
1693 case MEReconnectStart:
1694 case MEReconnectEnd:
1695 case MERendererEvent:
1696 case MEStreamSinkFormatChanged:
1698 media_player_create_forward_event(player, event_status, session_event, &event);
1700 break;
1702 case MEError:
1704 media_event_create(player, MFP_EVENT_TYPE_ERROR, event_status, NULL, &event);
1706 break;
1708 default:
1712 if (item)
1713 IMFPMediaItem_Release(item);
1715 if (event)
1717 media_player_queue_event(player, event);
1718 IUnknown_Release(&event->IUnknown_iface);
1721 IMFMediaSession_BeginGetEvent(player->session, &player->session_events_callback, NULL);
1722 IMFMediaEvent_Release(session_event);
1724 return S_OK;
1727 static const IMFAsyncCallbackVtbl media_player_session_events_callback_vtbl =
1729 media_player_callback_QueryInterface,
1730 media_player_session_events_callback_AddRef,
1731 media_player_session_events_callback_Release,
1732 media_player_callback_GetParameters,
1733 media_player_session_events_callback_Invoke,
1736 HRESULT WINAPI MFPCreateMediaPlayer(const WCHAR *url, BOOL start_playback, MFP_CREATION_OPTIONS options,
1737 IMFPMediaPlayerCallback *callback, HWND window, IMFPMediaPlayer **player)
1739 struct media_player *object;
1740 HRESULT hr;
1742 TRACE("%s, %d, %#x, %p, %p, %p.\n", debugstr_w(url), start_playback, options, callback, window, player);
1744 if (!(object = calloc(1, sizeof(*object))))
1745 return E_OUTOFMEMORY;
1747 platform_startup();
1749 object->IMFPMediaPlayer_iface.lpVtbl = &media_player_vtbl;
1750 object->IPropertyStore_iface.lpVtbl = &media_player_propstore_vtbl;
1751 object->resolver_callback.lpVtbl = &media_player_resolver_callback_vtbl;
1752 object->events_callback.lpVtbl = &media_player_events_callback_vtbl;
1753 object->session_events_callback.lpVtbl = &media_player_session_events_callback_vtbl;
1754 object->refcount = 1;
1755 object->callback = callback;
1756 if (object->callback)
1757 IMFPMediaPlayerCallback_AddRef(object->callback);
1758 object->options = options;
1759 object->output_window = window;
1760 InitializeCriticalSection(&object->cs);
1761 if (FAILED(hr = CreatePropertyStore(&object->propstore)))
1762 goto failed;
1763 if (FAILED(hr = MFCreateSourceResolver(&object->resolver)))
1764 goto failed;
1765 if (FAILED(hr = MFCreateMediaSession(NULL, &object->session)))
1766 goto failed;
1767 if (FAILED(hr = IMFMediaSession_BeginGetEvent(object->session, &object->session_events_callback, NULL)))
1768 goto failed;
1769 if (!(object->options & MFP_OPTION_FREE_THREADED_CALLBACK))
1771 object->event_window = CreateWindowW(eventclassW, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE,
1772 0, mfplay_instance, NULL);
1775 *player = &object->IMFPMediaPlayer_iface;
1777 return S_OK;
1779 failed:
1781 IMFPMediaPlayer_Release(&object->IMFPMediaPlayer_iface);
1783 return hr;
1786 static void media_player_register_window_class(void)
1788 WNDCLASSW cls = { 0 };
1790 cls.lpfnWndProc = media_player_event_proc;
1791 cls.hInstance = mfplay_instance;
1792 cls.lpszClassName = eventclassW;
1794 RegisterClassW(&cls);
1797 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
1799 switch (reason)
1801 case DLL_PROCESS_ATTACH:
1802 mfplay_instance = instance;
1803 DisableThreadLibraryCalls(instance);
1804 media_player_register_window_class();
1805 break;
1806 case DLL_PROCESS_DETACH:
1807 if (reserved) break;
1808 UnregisterClassW(eventclassW, instance);
1809 break;
1812 return TRUE;