mfplay: Implement SetStreamSink().
[wine.git] / dlls / mfplay / player.c
blob51f3f67f5b1f17f22bd1b2c4e17bebaba04cc6dc
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);
37 DEFINE_GUID(_MF_CUSTOM_SINK, 0x7c1bb4df, 0x59ba, 0x4020, 0x85, 0x0c, 0x35, 0x79, 0xa2, 0x7a, 0xe2, 0x51);
39 static const WCHAR eventclassW[] = L"MediaPlayerEventCallbackClass";
41 static LONG startup_refcount;
42 static HINSTANCE mfplay_instance;
44 static void platform_startup(void)
46 if (InterlockedIncrement(&startup_refcount) == 1)
47 MFStartup(MF_VERSION, MFSTARTUP_FULL);
50 static void platform_shutdown(void)
52 if (InterlockedDecrement(&startup_refcount) == 0)
53 MFShutdown();
56 struct media_item
58 IMFPMediaItem IMFPMediaItem_iface;
59 LONG refcount;
60 IMFPMediaPlayer *player;
61 IMFMediaSource *source;
62 IMFPresentationDescriptor *pd;
63 DWORD_PTR user_data;
64 WCHAR *url;
65 IUnknown *object;
68 struct media_player
70 IMFPMediaPlayer IMFPMediaPlayer_iface;
71 IPropertyStore IPropertyStore_iface;
72 IMFAsyncCallback resolver_callback;
73 IMFAsyncCallback events_callback;
74 IMFAsyncCallback session_events_callback;
75 LONG refcount;
76 IMFPMediaPlayerCallback *callback;
77 IPropertyStore *propstore;
78 IMFSourceResolver *resolver;
79 IMFMediaSession *session;
80 IMFPMediaItem *item;
81 MFP_CREATION_OPTIONS options;
82 MFP_MEDIAPLAYER_STATE state;
83 HWND event_window;
84 HWND output_window;
85 CRITICAL_SECTION cs;
88 struct generic_event
90 MFP_EVENT_HEADER header;
91 IMFPMediaItem *item;
94 struct media_event
96 IUnknown IUnknown_iface;
97 LONG refcount;
98 union
100 MFP_EVENT_HEADER header;
101 struct generic_event generic;
102 MFP_PLAY_EVENT play;
103 MFP_PAUSE_EVENT pause;
104 MFP_STOP_EVENT stop;
105 MFP_POSITION_SET_EVENT position_set;
106 MFP_RATE_SET_EVENT rate_set;
107 MFP_MEDIAITEM_CREATED_EVENT item_created;
108 MFP_MEDIAITEM_SET_EVENT item_set;
109 MFP_MEDIAITEM_CLEARED_EVENT item_cleared;
110 MFP_MF_EVENT event;
111 MFP_ERROR_EVENT error;
112 MFP_PLAYBACK_ENDED_EVENT ended;
113 MFP_ACQUIRE_USER_CREDENTIAL_EVENT acquire_creds;
114 } u;
117 static struct media_player *impl_from_IMFPMediaPlayer(IMFPMediaPlayer *iface)
119 return CONTAINING_RECORD(iface, struct media_player, IMFPMediaPlayer_iface);
122 static struct media_player *impl_from_IPropertyStore(IPropertyStore *iface)
124 return CONTAINING_RECORD(iface, struct media_player, IPropertyStore_iface);
127 static struct media_player *impl_from_resolver_IMFAsyncCallback(IMFAsyncCallback *iface)
129 return CONTAINING_RECORD(iface, struct media_player, resolver_callback);
132 static struct media_player *impl_from_events_IMFAsyncCallback(IMFAsyncCallback *iface)
134 return CONTAINING_RECORD(iface, struct media_player, events_callback);
137 static struct media_player *impl_from_session_events_IMFAsyncCallback(IMFAsyncCallback *iface)
139 return CONTAINING_RECORD(iface, struct media_player, session_events_callback);
142 static struct media_item *impl_from_IMFPMediaItem(IMFPMediaItem *iface)
144 return CONTAINING_RECORD(iface, struct media_item, IMFPMediaItem_iface);
147 static struct media_event *impl_event_from_IUnknown(IUnknown *iface)
149 return CONTAINING_RECORD(iface, struct media_event, IUnknown_iface);
152 static HRESULT WINAPI media_event_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
154 if (IsEqualIID(riid, &IID_IUnknown))
156 *obj = iface;
157 IUnknown_AddRef(iface);
158 return S_OK;
161 *obj = NULL;
162 return E_NOINTERFACE;
165 static ULONG WINAPI media_event_AddRef(IUnknown *iface)
167 struct media_event *event = impl_event_from_IUnknown(iface);
168 ULONG refcount = InterlockedIncrement(&event->refcount);
170 TRACE("%p, refcount %u.\n", iface, refcount);
172 return refcount;
175 static ULONG WINAPI media_event_Release(IUnknown *iface)
177 struct media_event *event = impl_event_from_IUnknown(iface);
178 ULONG refcount = InterlockedDecrement(&event->refcount);
180 TRACE("%p, refcount %u.\n", iface, refcount);
182 if (!refcount)
184 if (event->u.header.pMediaPlayer)
185 IMFPMediaPlayer_Release(event->u.header.pMediaPlayer);
186 if (event->u.header.pPropertyStore)
187 IPropertyStore_Release(event->u.header.pPropertyStore);
189 switch (event->u.header.eEventType)
191 /* Most types share same layout. */
192 case MFP_EVENT_TYPE_PLAY:
193 case MFP_EVENT_TYPE_PAUSE:
194 case MFP_EVENT_TYPE_STOP:
195 case MFP_EVENT_TYPE_POSITION_SET:
196 case MFP_EVENT_TYPE_RATE_SET:
197 case MFP_EVENT_TYPE_MEDIAITEM_CREATED:
198 case MFP_EVENT_TYPE_MEDIAITEM_SET:
199 case MFP_EVENT_TYPE_FRAME_STEP:
200 case MFP_EVENT_TYPE_MEDIAITEM_CLEARED:
201 case MFP_EVENT_TYPE_PLAYBACK_ENDED:
202 if (event->u.generic.item)
203 IMFPMediaItem_Release(event->u.generic.item);
204 break;
205 case MFP_EVENT_TYPE_MF:
206 if (event->u.event.pMFMediaEvent)
207 IMFMediaEvent_Release(event->u.event.pMFMediaEvent);
208 if (event->u.event.pMediaItem)
209 IMFPMediaItem_Release(event->u.event.pMediaItem);
210 break;
211 default:
212 FIXME("Unsupported event %u.\n", event->u.header.eEventType);
213 break;
216 free(event);
219 return refcount;
222 static const IUnknownVtbl media_event_vtbl =
224 media_event_QueryInterface,
225 media_event_AddRef,
226 media_event_Release,
229 static HRESULT media_event_create(struct media_player *player, MFP_EVENT_TYPE event_type,
230 HRESULT hr, IMFPMediaItem *item, struct media_event **event)
232 struct media_event *object;
234 if (!(object = calloc(1, sizeof(*object))))
235 return E_OUTOFMEMORY;
237 object->IUnknown_iface.lpVtbl = &media_event_vtbl;
238 object->refcount = 1;
239 object->u.header.eEventType = event_type;
240 object->u.header.hrEvent = hr;
241 object->u.header.pMediaPlayer = &player->IMFPMediaPlayer_iface;
242 IMFPMediaPlayer_AddRef(object->u.header.pMediaPlayer);
243 object->u.header.eState = player->state;
244 switch (event_type)
246 case MFP_EVENT_TYPE_PLAY:
247 case MFP_EVENT_TYPE_PAUSE:
248 case MFP_EVENT_TYPE_STOP:
249 case MFP_EVENT_TYPE_POSITION_SET:
250 case MFP_EVENT_TYPE_RATE_SET:
251 case MFP_EVENT_TYPE_MEDIAITEM_CREATED:
252 case MFP_EVENT_TYPE_MEDIAITEM_SET:
253 case MFP_EVENT_TYPE_FRAME_STEP:
254 case MFP_EVENT_TYPE_MEDIAITEM_CLEARED:
255 case MFP_EVENT_TYPE_PLAYBACK_ENDED:
256 object->u.generic.item = item;
257 if (object->u.generic.item)
258 IMFPMediaItem_AddRef(object->u.generic.item);
259 break;
260 case MFP_EVENT_TYPE_MF:
261 object->u.event.pMediaItem = item;
262 if (object->u.event.pMediaItem)
263 IMFPMediaItem_AddRef(object->u.event.pMediaItem);
264 break;
265 default:
269 /* FIXME: set properties for some events? */
271 *event = object;
273 return S_OK;
276 static LRESULT WINAPI media_player_event_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
278 struct media_event *event = (void *)lparam;
279 struct media_player *player;
281 if (msg == WM_USER)
283 player = impl_from_IMFPMediaPlayer(event->u.header.pMediaPlayer);
284 if (player->callback)
285 IMFPMediaPlayerCallback_OnMediaPlayerEvent(player->callback, &event->u.header);
286 IUnknown_Release(&event->IUnknown_iface);
287 return 0;
290 return DefWindowProcW(hwnd, msg, wparam, lparam);
293 static void media_player_set_state(struct media_player *player, MFP_MEDIAPLAYER_STATE state)
295 if (player->state != MFP_MEDIAPLAYER_STATE_SHUTDOWN)
297 if (state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
298 IMFMediaSession_Shutdown(player->session);
299 player->state = state;
303 static HRESULT WINAPI media_item_QueryInterface(IMFPMediaItem *iface, REFIID riid, void **obj)
305 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
307 if (IsEqualIID(riid, &IID_IMFPMediaItem) ||
308 IsEqualIID(riid, &IID_IUnknown))
310 *obj = iface;
311 IMFPMediaItem_AddRef(iface);
312 return S_OK;
315 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
316 *obj = NULL;
317 return E_NOINTERFACE;
320 static ULONG WINAPI media_item_AddRef(IMFPMediaItem *iface)
322 struct media_item *item = impl_from_IMFPMediaItem(iface);
323 ULONG refcount = InterlockedIncrement(&item->refcount);
325 TRACE("%p, refcount %u.\n", iface, refcount);
327 return refcount;
330 static ULONG WINAPI media_item_Release(IMFPMediaItem *iface)
332 struct media_item *item = impl_from_IMFPMediaItem(iface);
333 ULONG refcount = InterlockedDecrement(&item->refcount);
335 TRACE("%p, refcount %u.\n", iface, refcount);
337 if (!refcount)
339 if (item->player)
340 IMFPMediaPlayer_Release(item->player);
341 if (item->source)
342 IMFMediaSource_Release(item->source);
343 if (item->pd)
344 IMFPresentationDescriptor_Release(item->pd);
345 if (item->object)
346 IUnknown_Release(item->object);
347 free(item->url);
348 free(item);
351 return refcount;
354 static HRESULT WINAPI media_item_GetMediaPlayer(IMFPMediaItem *iface,
355 IMFPMediaPlayer **player)
357 struct media_item *item = impl_from_IMFPMediaItem(iface);
359 TRACE("%p, %p.\n", iface, player);
361 *player = item->player;
362 IMFPMediaPlayer_AddRef(*player);
364 return S_OK;
367 static HRESULT WINAPI media_item_GetURL(IMFPMediaItem *iface, LPWSTR *url)
369 struct media_item *item = impl_from_IMFPMediaItem(iface);
371 TRACE("%p, %p.\n", iface, url);
373 if (!item->url)
374 return MF_E_NOT_FOUND;
376 if (!(*url = CoTaskMemAlloc((wcslen(item->url) + 1) * sizeof(*item->url))))
377 return E_OUTOFMEMORY;
379 wcscpy(*url, item->url);
381 return S_OK;
384 static HRESULT WINAPI media_item_GetObject(IMFPMediaItem *iface, IUnknown **object)
386 struct media_item *item = impl_from_IMFPMediaItem(iface);
388 TRACE("%p, %p.\n", iface, object);
390 if (!item->object)
391 return MF_E_NOT_FOUND;
393 *object = item->object;
394 IUnknown_AddRef(*object);
396 return S_OK;
399 static HRESULT WINAPI media_item_GetUserData(IMFPMediaItem *iface, DWORD_PTR *user_data)
401 struct media_item *item = impl_from_IMFPMediaItem(iface);
403 TRACE("%p, %p.\n", iface, user_data);
405 *user_data = item->user_data;
407 return S_OK;
410 static HRESULT WINAPI media_item_SetUserData(IMFPMediaItem *iface, DWORD_PTR user_data)
412 struct media_item *item = impl_from_IMFPMediaItem(iface);
414 TRACE("%p, %lx.\n", iface, user_data);
416 item->user_data = user_data;
418 return S_OK;
421 static HRESULT WINAPI media_item_GetStartStopPosition(IMFPMediaItem *iface, GUID *start_format,
422 PROPVARIANT *start_position, GUID *stop_format, PROPVARIANT *stop_position)
424 FIXME("%p, %p, %p, %p, %p.\n", iface, start_format, start_position, stop_format, stop_position);
426 return E_NOTIMPL;
429 static HRESULT WINAPI media_item_SetStartStopPosition(IMFPMediaItem *iface, const GUID *start_format,
430 const PROPVARIANT *start_position, const GUID *stop_format, const PROPVARIANT *stop_position)
432 FIXME("%p, %s, %p, %s, %p.\n", iface, debugstr_guid(start_format), start_position,
433 debugstr_guid(stop_format), stop_position);
435 return E_NOTIMPL;
438 static HRESULT WINAPI media_item_HasVideo(IMFPMediaItem *iface, BOOL *has_video, BOOL *selected)
440 FIXME("%p, %p, %p.\n", iface, has_video, selected);
442 return E_NOTIMPL;
445 static HRESULT WINAPI media_item_HasAudio(IMFPMediaItem *iface, BOOL *has_audio, BOOL *selected)
447 FIXME("%p, %p, %p.\n", iface, has_audio, selected);
449 return E_NOTIMPL;
452 static HRESULT WINAPI media_item_IsProtected(IMFPMediaItem *iface, BOOL *protected)
454 struct media_item *item = impl_from_IMFPMediaItem(iface);
456 TRACE("%p, %p.\n", iface, protected);
458 *protected = MFRequireProtectedEnvironment(item->pd) == S_OK;
460 return S_OK;
463 static HRESULT WINAPI media_item_GetDuration(IMFPMediaItem *iface, REFGUID format, PROPVARIANT *value)
465 struct media_item *item = impl_from_IMFPMediaItem(iface);
467 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), value);
469 return IMFPresentationDescriptor_GetItem(item->pd, &MF_PD_DURATION, value);
472 static HRESULT WINAPI media_item_GetNumberOfStreams(IMFPMediaItem *iface, DWORD *count)
474 struct media_item *item = impl_from_IMFPMediaItem(iface);
476 TRACE("%p, %p.\n", iface, count);
478 return IMFPresentationDescriptor_GetStreamDescriptorCount(item->pd, count);
481 static HRESULT WINAPI media_item_GetStreamSelection(IMFPMediaItem *iface, DWORD index, BOOL *selected)
483 struct media_item *item = impl_from_IMFPMediaItem(iface);
484 IMFStreamDescriptor *sd;
485 HRESULT hr;
487 TRACE("%p, %u, %p.\n", iface, index, selected);
489 if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, index, selected, &sd)))
490 IMFStreamDescriptor_Release(sd);
492 return hr;
495 static HRESULT WINAPI media_item_SetStreamSelection(IMFPMediaItem *iface, DWORD index, BOOL select)
497 struct media_item *item = impl_from_IMFPMediaItem(iface);
499 TRACE("%p, %u, %d.\n", iface, index, select);
501 return select ? IMFPresentationDescriptor_SelectStream(item->pd, index) :
502 IMFPresentationDescriptor_DeselectStream(item->pd, index);
505 static HRESULT WINAPI media_item_GetStreamAttribute(IMFPMediaItem *iface, DWORD index, REFGUID key,
506 PROPVARIANT *value)
508 struct media_item *item = impl_from_IMFPMediaItem(iface);
509 IMFStreamDescriptor *sd;
510 BOOL selected;
511 HRESULT hr;
513 TRACE("%p, %u, %s, %p.\n", iface, index, debugstr_guid(key), value);
515 if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, index, &selected, &sd)))
517 hr = IMFStreamDescriptor_GetItem(sd, key, value);
518 IMFStreamDescriptor_Release(sd);
521 return hr;
524 static HRESULT WINAPI media_item_GetPresentationAttribute(IMFPMediaItem *iface, REFGUID key,
525 PROPVARIANT *value)
527 struct media_item *item = impl_from_IMFPMediaItem(iface);
529 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
531 return IMFPresentationDescriptor_GetItem(item->pd, key, value);
534 static HRESULT WINAPI media_item_GetCharacteristics(IMFPMediaItem *iface, MFP_MEDIAITEM_CHARACTERISTICS *flags)
536 struct media_item *item = impl_from_IMFPMediaItem(iface);
537 HRESULT hr;
539 TRACE("%p, %p.\n", iface, flags);
541 *flags = 0;
543 if (SUCCEEDED(hr = IMFMediaSource_GetCharacteristics(item->source, flags)))
545 *flags &= (MFP_MEDIAITEM_IS_LIVE | MFP_MEDIAITEM_CAN_SEEK |
546 MFP_MEDIAITEM_CAN_PAUSE | MFP_MEDIAITEM_HAS_SLOW_SEEK);
549 return hr;
552 static HRESULT WINAPI media_item_SetStreamSink(IMFPMediaItem *iface, DWORD index, IUnknown *sink)
554 struct media_item *item = impl_from_IMFPMediaItem(iface);
555 IMFStreamDescriptor *sd;
556 IUnknown *sink_object;
557 BOOL selected;
558 HRESULT hr;
560 TRACE("%p, %u, %p.\n", iface, index, sink);
562 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, index, &selected, &sd)))
563 return hr;
565 if (sink)
567 if (FAILED(hr = IUnknown_QueryInterface(sink, &IID_IMFStreamSink, (void **)&sink_object)))
568 hr = IUnknown_QueryInterface(sink, &IID_IMFActivate, (void **)&sink_object);
570 if (sink_object)
572 hr = IMFStreamDescriptor_SetUnknown(sd, &_MF_CUSTOM_SINK, sink_object);
573 IUnknown_Release(sink_object);
576 else
577 IMFStreamDescriptor_DeleteItem(sd, &_MF_CUSTOM_SINK);
579 IMFStreamDescriptor_Release(sd);
581 return hr;
584 static HRESULT WINAPI media_item_GetMetadata(IMFPMediaItem *iface, IPropertyStore **metadata)
586 struct media_item *item = impl_from_IMFPMediaItem(iface);
588 TRACE("%p, %p.\n", iface, metadata);
590 return MFGetService((IUnknown *)item->source, &MF_PROPERTY_HANDLER_SERVICE,
591 &IID_IPropertyStore, (void **)&metadata);
594 static const IMFPMediaItemVtbl media_item_vtbl =
596 media_item_QueryInterface,
597 media_item_AddRef,
598 media_item_Release,
599 media_item_GetMediaPlayer,
600 media_item_GetURL,
601 media_item_GetObject,
602 media_item_GetUserData,
603 media_item_SetUserData,
604 media_item_GetStartStopPosition,
605 media_item_SetStartStopPosition,
606 media_item_HasVideo,
607 media_item_HasAudio,
608 media_item_IsProtected,
609 media_item_GetDuration,
610 media_item_GetNumberOfStreams,
611 media_item_GetStreamSelection,
612 media_item_SetStreamSelection,
613 media_item_GetStreamAttribute,
614 media_item_GetPresentationAttribute,
615 media_item_GetCharacteristics,
616 media_item_SetStreamSink,
617 media_item_GetMetadata,
620 static struct media_item *unsafe_impl_from_IMFPMediaItem(IMFPMediaItem *iface)
622 if (!iface)
623 return NULL;
624 assert(iface->lpVtbl == (IMFPMediaItemVtbl *)&media_item_vtbl);
625 return CONTAINING_RECORD(iface, struct media_item, IMFPMediaItem_iface);
628 static HRESULT create_media_item(IMFPMediaPlayer *player, DWORD_PTR user_data, struct media_item **item)
630 struct media_item *object;
632 if (!(object = calloc(1, sizeof(*object))))
633 return E_OUTOFMEMORY;
635 object->IMFPMediaItem_iface.lpVtbl = &media_item_vtbl;
636 object->refcount = 1;
637 object->user_data = user_data;
638 object->player = player;
639 IMFPMediaPlayer_AddRef(object->player);
641 *item = object;
643 return S_OK;
646 static HRESULT media_item_set_source(struct media_item *item, IUnknown *object)
648 IMFPresentationDescriptor *pd;
649 IMFMediaSource *source;
650 HRESULT hr;
652 if (FAILED(hr = IUnknown_QueryInterface(object, &IID_IMFMediaSource, (void **)&source)))
653 return hr;
655 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd)))
657 WARN("Failed to get presentation descriptor, hr %#x.\n", hr);
658 IMFMediaSource_Release(source);
659 return hr;
662 item->source = source;
663 item->pd = pd;
665 return hr;
668 static void media_player_queue_event(struct media_player *player, struct media_event *event)
670 if (player->options & MFP_OPTION_FREE_THREADED_CALLBACK)
672 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, &player->events_callback, &event->IUnknown_iface);
674 else
676 IUnknown_AddRef(&event->IUnknown_iface);
677 PostMessageW(player->event_window, WM_USER, 0, (LPARAM)event);
681 static HRESULT WINAPI media_player_QueryInterface(IMFPMediaPlayer *iface, REFIID riid, void **obj)
683 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
685 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
687 if (IsEqualIID(riid, &IID_IMFPMediaPlayer) ||
688 IsEqualIID(riid, &IID_IUnknown))
690 *obj = &player->IMFPMediaPlayer_iface;
692 else if (IsEqualIID(riid, &IID_IPropertyStore))
694 *obj = &player->IPropertyStore_iface;
696 else
698 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
699 *obj = NULL;
701 return E_NOINTERFACE;
704 IUnknown_AddRef((IUnknown *)*obj);
705 return S_OK;
708 static ULONG WINAPI media_player_AddRef(IMFPMediaPlayer *iface)
710 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
711 ULONG refcount = InterlockedIncrement(&player->refcount);
713 TRACE("%p, refcount %u.\n", iface, refcount);
715 return refcount;
718 static ULONG WINAPI media_player_Release(IMFPMediaPlayer *iface)
720 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
721 ULONG refcount = InterlockedDecrement(&player->refcount);
723 TRACE("%p, refcount %u.\n", iface, refcount);
725 if (!refcount)
727 if (player->callback)
728 IMFPMediaPlayerCallback_Release(player->callback);
729 if (player->propstore)
730 IPropertyStore_Release(player->propstore);
731 if (player->resolver)
732 IMFSourceResolver_Release(player->resolver);
733 if (player->session)
734 IMFMediaSession_Release(player->session);
735 DestroyWindow(player->event_window);
736 DeleteCriticalSection(&player->cs);
737 free(player);
739 platform_shutdown();
742 return refcount;
745 static HRESULT WINAPI media_player_Play(IMFPMediaPlayer *iface)
747 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
748 PROPVARIANT pos;
750 TRACE("%p.\n", iface);
752 pos.vt = VT_EMPTY;
753 return IMFMediaSession_Start(player->session, &GUID_NULL, &pos);
756 static HRESULT WINAPI media_player_Pause(IMFPMediaPlayer *iface)
758 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
760 TRACE("%p.\n", iface);
762 return IMFMediaSession_Pause(player->session);
765 static HRESULT WINAPI media_player_Stop(IMFPMediaPlayer *iface)
767 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
769 TRACE("%p.\n", iface);
771 return IMFMediaSession_Stop(player->session);
774 static HRESULT WINAPI media_player_FrameStep(IMFPMediaPlayer *iface)
776 FIXME("%p.\n", iface);
778 return E_NOTIMPL;
781 static HRESULT WINAPI media_player_SetPosition(IMFPMediaPlayer *iface, REFGUID postype, const PROPVARIANT *position)
783 FIXME("%p, %s, %p.\n", iface, debugstr_guid(postype), position);
785 return E_NOTIMPL;
788 static HRESULT WINAPI media_player_GetPosition(IMFPMediaPlayer *iface, REFGUID postype, PROPVARIANT *position)
790 FIXME("%p, %s, %p.\n", iface, debugstr_guid(postype), position);
792 return E_NOTIMPL;
795 static HRESULT WINAPI media_player_GetDuration(IMFPMediaPlayer *iface, REFGUID postype, PROPVARIANT *position)
797 FIXME("%p, %s, %p.\n", iface, debugstr_guid(postype), position);
799 return E_NOTIMPL;
802 static HRESULT WINAPI media_player_SetRate(IMFPMediaPlayer *iface, float rate)
804 FIXME("%p, %f.\n", iface, rate);
806 return E_NOTIMPL;
809 static HRESULT WINAPI media_player_GetRate(IMFPMediaPlayer *iface, float *rate)
811 FIXME("%p, %p.\n", iface, rate);
813 return E_NOTIMPL;
816 static HRESULT WINAPI media_player_GetSupportedRates(IMFPMediaPlayer *iface, BOOL forward,
817 float *slowest_rate, float *fastest_rate)
819 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
820 IMFRateSupport *rs;
821 HRESULT hr;
823 TRACE("%p, %d, %p, %p.\n", iface, forward, slowest_rate, fastest_rate);
825 if (SUCCEEDED(hr = MFGetService((IUnknown *)player->session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rs)))
827 if (SUCCEEDED(hr = IMFRateSupport_GetSlowestRate(rs, forward ? MFRATE_FORWARD : MFRATE_REVERSE, FALSE, slowest_rate)))
828 hr = IMFRateSupport_GetFastestRate(rs, forward ? MFRATE_FORWARD : MFRATE_REVERSE, FALSE, fastest_rate);
829 IMFRateSupport_Release(rs);
832 return hr;
835 static HRESULT WINAPI media_player_GetState(IMFPMediaPlayer *iface, MFP_MEDIAPLAYER_STATE *state)
837 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
839 TRACE("%p, %p.\n", iface, state);
841 *state = player->state;
843 return S_OK;
846 static HRESULT media_player_create_item_from_url(struct media_player *player,
847 const WCHAR *url, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **ret)
849 struct media_item *item;
850 MF_OBJECT_TYPE obj_type;
851 IUnknown *object;
852 HRESULT hr;
854 *ret = NULL;
856 if (FAILED(hr = create_media_item(&player->IMFPMediaPlayer_iface, user_data, &item)))
857 return hr;
859 if (url && !(item->url = wcsdup(url)))
861 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
862 return E_OUTOFMEMORY;
865 if (sync)
867 if (SUCCEEDED(hr = IMFSourceResolver_CreateObjectFromURL(player->resolver, url, MF_RESOLUTION_MEDIASOURCE,
868 player->propstore, &obj_type, &object)))
870 hr = media_item_set_source(item, object);
871 IUnknown_Release(object);
874 if (SUCCEEDED(hr))
876 *ret = &item->IMFPMediaItem_iface;
877 IMFPMediaItem_AddRef(*ret);
880 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
882 return hr;
884 else
886 hr = IMFSourceResolver_BeginCreateObjectFromURL(player->resolver, url, MF_RESOLUTION_MEDIASOURCE,
887 player->propstore, NULL, &player->resolver_callback, (IUnknown *)&item->IMFPMediaItem_iface);
889 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
892 return hr;
895 static HRESULT WINAPI media_player_CreateMediaItemFromURL(IMFPMediaPlayer *iface,
896 const WCHAR *url, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **item)
898 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
899 HRESULT hr;
901 TRACE("%p, %s, %d, %lx, %p.\n", iface, debugstr_w(url), sync, user_data, item);
903 EnterCriticalSection(&player->cs);
904 if (player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
905 hr = MF_E_SHUTDOWN;
906 else
907 hr = media_player_create_item_from_url(player, url, sync, user_data, item);
908 LeaveCriticalSection(&player->cs);
910 return hr;
913 static HRESULT media_player_create_item_from_object(struct media_player *player,
914 IUnknown *object, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **ret)
916 struct media_item *item;
917 MF_OBJECT_TYPE obj_type;
918 HRESULT hr;
919 IMFByteStream *stream = NULL;
920 IMFMediaSource *source = NULL;
922 *ret = NULL;
924 if (FAILED(hr = create_media_item(&player->IMFPMediaPlayer_iface, user_data, &item)))
925 return hr;
927 item->object = object;
928 IUnknown_AddRef(item->object);
930 if (FAILED(IUnknown_QueryInterface(object, &IID_IMFMediaSource, (void **)&source)))
931 IUnknown_QueryInterface(object, &IID_IMFByteStream, (void **)&stream);
933 if (!source && !stream)
935 WARN("Unsupported object type.\n");
936 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
937 return E_UNEXPECTED;
940 if (sync)
942 if (stream)
943 hr = IMFSourceResolver_CreateObjectFromByteStream(player->resolver, stream, NULL,
944 MF_RESOLUTION_MEDIASOURCE, player->propstore, &obj_type, &object);
945 else
946 IUnknown_AddRef(object);
948 if (SUCCEEDED(hr))
949 hr = media_item_set_source(item, object);
951 IUnknown_Release(object);
953 if (SUCCEEDED(hr))
955 *ret = &item->IMFPMediaItem_iface;
956 IMFPMediaItem_AddRef(*ret);
959 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
961 else
963 if (stream)
965 hr = IMFSourceResolver_BeginCreateObjectFromByteStream(player->resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE,
966 player->propstore, NULL, &player->resolver_callback, (IUnknown *)&item->IMFPMediaItem_iface);
968 else
970 /* Resolver callback will check again if item's object is a source. */
971 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, &player->resolver_callback,
972 (IUnknown *)&item->IMFPMediaItem_iface);
975 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
978 if (source)
979 IMFMediaSource_Release(source);
980 if (stream)
981 IMFByteStream_Release(stream);
983 return hr;
986 static HRESULT WINAPI media_player_CreateMediaItemFromObject(IMFPMediaPlayer *iface,
987 IUnknown *object, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **item)
989 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
990 HRESULT hr;
992 TRACE("%p, %p, %d, %lx, %p.\n", iface, object, sync, user_data, item);
994 EnterCriticalSection(&player->cs);
995 if (player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
996 hr = MF_E_SHUTDOWN;
997 else
998 hr = media_player_create_item_from_object(player, object, sync, user_data, item);
999 LeaveCriticalSection(&player->cs);
1001 return hr;
1004 static HRESULT media_item_get_stream_type(IMFStreamDescriptor *sd, GUID *major)
1006 IMFMediaTypeHandler *handler;
1007 HRESULT hr;
1009 if (SUCCEEDED(hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler)))
1011 hr = IMFMediaTypeHandler_GetMajorType(handler, major);
1012 IMFMediaTypeHandler_Release(handler);
1015 return hr;
1018 static HRESULT media_item_create_topology(struct media_player *player, struct media_item *item, IMFTopology **out)
1020 IMFTopologyNode *src_node, *sink_node;
1021 IMFActivate *sar_activate;
1022 IMFStreamDescriptor *sd;
1023 IMFTopology *topology;
1024 unsigned int idx;
1025 BOOL selected;
1026 HRESULT hr;
1027 GUID major;
1029 if (FAILED(hr = MFCreateTopology(&topology)))
1030 return hr;
1032 /* FIXME: handle user sinks */
1034 /* Use first stream if none selected. */
1035 if (player->output_window)
1037 FIXME("Video streams are not handled.\n");
1040 /* Set up audio branches for all selected streams. */
1042 idx = 0;
1043 while (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, idx++, &selected, &sd)))
1045 if (selected && SUCCEEDED(media_item_get_stream_type(sd, &major)) && IsEqualGUID(&major, &MFMediaType_Audio))
1047 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &src_node)))
1049 IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_SOURCE, (IUnknown *)item->source);
1050 IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)item->pd);
1051 IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd);
1053 IMFTopology_AddNode(topology, src_node);
1056 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &sink_node)))
1058 if (SUCCEEDED(MFCreateAudioRendererActivate(&sar_activate)))
1060 IMFTopologyNode_SetObject(sink_node, (IUnknown *)sar_activate);
1061 IMFActivate_Release(sar_activate);
1064 IMFTopology_AddNode(topology, sink_node);
1067 if (src_node && sink_node)
1068 IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0);
1070 if (src_node)
1071 IMFTopologyNode_Release(src_node);
1072 if (sink_node)
1073 IMFTopologyNode_Release(sink_node);
1076 IMFStreamDescriptor_Release(sd);
1079 *out = topology;
1081 return S_OK;
1084 static HRESULT WINAPI media_player_SetMediaItem(IMFPMediaPlayer *iface, IMFPMediaItem *item_iface)
1086 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1087 struct media_item *item = unsafe_impl_from_IMFPMediaItem(item_iface);
1088 IMFTopology *topology;
1089 HRESULT hr;
1091 TRACE("%p, %p.\n", iface, item_iface);
1093 if (item->player != iface)
1094 return E_INVALIDARG;
1096 if (FAILED(hr = media_item_create_topology(player, item, &topology)))
1097 return hr;
1099 IMFTopology_SetUnknown(topology, &_MF_TOPO_MEDIA_ITEM, (IUnknown *)item_iface);
1100 hr = IMFMediaSession_SetTopology(player->session, MFSESSION_SETTOPOLOGY_IMMEDIATE, topology);
1101 IMFTopology_Release(topology);
1103 return hr;
1106 static HRESULT WINAPI media_player_ClearMediaItem(IMFPMediaPlayer *iface)
1108 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1110 TRACE("%p.\n", iface);
1112 return IMFMediaSession_SetTopology(player->session, MFSESSION_SETTOPOLOGY_CLEAR_CURRENT, NULL);
1115 static HRESULT WINAPI media_player_GetMediaItem(IMFPMediaPlayer *iface, IMFPMediaItem **item)
1117 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1118 HRESULT hr = S_OK;
1120 TRACE("%p, %p.\n", iface, item);
1122 if (!item)
1123 return E_POINTER;
1125 EnterCriticalSection(&player->cs);
1126 if (player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
1127 hr = MF_E_SHUTDOWN;
1128 else if (!player->item)
1129 hr = MF_E_NOT_FOUND;
1130 else
1132 *item = player->item;
1133 IMFPMediaItem_AddRef(player->item);
1135 LeaveCriticalSection(&player->cs);
1137 return hr;
1140 static HRESULT WINAPI media_player_GetVolume(IMFPMediaPlayer *iface, float *volume)
1142 FIXME("%p, %p.\n", iface, volume);
1144 return E_NOTIMPL;
1147 static HRESULT WINAPI media_player_SetVolume(IMFPMediaPlayer *iface, float volume)
1149 FIXME("%p, %.8e.\n", iface, volume);
1151 return E_NOTIMPL;
1154 static HRESULT WINAPI media_player_GetBalance(IMFPMediaPlayer *iface, float *balance)
1156 FIXME("%p, %p.\n", iface, balance);
1158 return E_NOTIMPL;
1161 static HRESULT WINAPI media_player_SetBalance(IMFPMediaPlayer *iface, float balance)
1163 FIXME("%p, %.8e.\n", iface, balance);
1165 return E_NOTIMPL;
1168 static HRESULT WINAPI media_player_GetMute(IMFPMediaPlayer *iface, BOOL *mute)
1170 FIXME("%p, %p.\n", iface, mute);
1172 return E_NOTIMPL;
1175 static HRESULT WINAPI media_player_SetMute(IMFPMediaPlayer *iface, BOOL mute)
1177 FIXME("%p, %d.\n", iface, mute);
1179 return E_NOTIMPL;
1182 static HRESULT WINAPI media_player_GetNativeVideoSize(IMFPMediaPlayer *iface,
1183 SIZE *video, SIZE *arvideo)
1185 FIXME("%p, %p, %p.\n", iface, video, arvideo);
1187 return E_NOTIMPL;
1190 static HRESULT WINAPI media_player_GetIdealVideoSize(IMFPMediaPlayer *iface,
1191 SIZE *min_size, SIZE *max_size)
1193 FIXME("%p, %p, %p.\n", iface, min_size, max_size);
1195 return E_NOTIMPL;
1198 static HRESULT WINAPI media_player_SetVideoSourceRect(IMFPMediaPlayer *iface,
1199 MFVideoNormalizedRect const *rect)
1201 FIXME("%p, %p.\n", iface, rect);
1203 return E_NOTIMPL;
1206 static HRESULT WINAPI media_player_GetVideoSourceRect(IMFPMediaPlayer *iface,
1207 MFVideoNormalizedRect *rect)
1209 FIXME("%p, %p.\n", iface, rect);
1211 return E_NOTIMPL;
1214 static HRESULT WINAPI media_player_SetAspectRatioMode(IMFPMediaPlayer *iface, DWORD mode)
1216 FIXME("%p, %u.\n", iface, mode);
1218 return E_NOTIMPL;
1221 static HRESULT WINAPI media_player_GetAspectRatioMode(IMFPMediaPlayer *iface,
1222 DWORD *mode)
1224 FIXME("%p, %p.\n", iface, mode);
1226 return E_NOTIMPL;
1229 static HRESULT WINAPI media_player_GetVideoWindow(IMFPMediaPlayer *iface, HWND *window)
1231 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1233 TRACE("%p, %p.\n", iface, window);
1235 *window = player->output_window;
1237 return S_OK;
1240 static HRESULT WINAPI media_player_UpdateVideo(IMFPMediaPlayer *iface)
1242 FIXME("%p.\n", iface);
1244 return E_NOTIMPL;
1247 static HRESULT WINAPI media_player_SetBorderColor(IMFPMediaPlayer *iface, COLORREF color)
1249 FIXME("%p, %#x.\n", iface, color);
1251 return E_NOTIMPL;
1254 static HRESULT WINAPI media_player_GetBorderColor(IMFPMediaPlayer *iface, COLORREF *color)
1256 FIXME("%p, %p.\n", iface, color);
1258 return E_NOTIMPL;
1261 static HRESULT WINAPI media_player_InsertEffect(IMFPMediaPlayer *iface, IUnknown *effect,
1262 BOOL optional)
1264 FIXME("%p, %p, %d.\n", iface, effect, optional);
1266 return E_NOTIMPL;
1269 static HRESULT WINAPI media_player_RemoveEffect(IMFPMediaPlayer *iface, IUnknown *effect)
1271 FIXME("%p, %p.\n", iface, effect);
1273 return E_NOTIMPL;
1276 static HRESULT WINAPI media_player_RemoveAllEffects(IMFPMediaPlayer *iface)
1278 FIXME("%p.\n", iface);
1280 return E_NOTIMPL;
1283 static HRESULT WINAPI media_player_Shutdown(IMFPMediaPlayer *iface)
1285 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1287 TRACE("%p.\n", iface);
1289 EnterCriticalSection(&player->cs);
1290 media_player_set_state(player, MFP_MEDIAPLAYER_STATE_SHUTDOWN);
1291 if (player->item)
1293 IMFPMediaItem_Release(player->item);
1294 player->item = NULL;
1296 LeaveCriticalSection(&player->cs);
1298 return S_OK;
1301 static const IMFPMediaPlayerVtbl media_player_vtbl =
1303 media_player_QueryInterface,
1304 media_player_AddRef,
1305 media_player_Release,
1306 media_player_Play,
1307 media_player_Pause,
1308 media_player_Stop,
1309 media_player_FrameStep,
1310 media_player_SetPosition,
1311 media_player_GetPosition,
1312 media_player_GetDuration,
1313 media_player_SetRate,
1314 media_player_GetRate,
1315 media_player_GetSupportedRates,
1316 media_player_GetState,
1317 media_player_CreateMediaItemFromURL,
1318 media_player_CreateMediaItemFromObject,
1319 media_player_SetMediaItem,
1320 media_player_ClearMediaItem,
1321 media_player_GetMediaItem,
1322 media_player_GetVolume,
1323 media_player_SetVolume,
1324 media_player_GetBalance,
1325 media_player_SetBalance,
1326 media_player_GetMute,
1327 media_player_SetMute,
1328 media_player_GetNativeVideoSize,
1329 media_player_GetIdealVideoSize,
1330 media_player_SetVideoSourceRect,
1331 media_player_GetVideoSourceRect,
1332 media_player_SetAspectRatioMode,
1333 media_player_GetAspectRatioMode,
1334 media_player_GetVideoWindow,
1335 media_player_UpdateVideo,
1336 media_player_SetBorderColor,
1337 media_player_GetBorderColor,
1338 media_player_InsertEffect,
1339 media_player_RemoveEffect,
1340 media_player_RemoveAllEffects,
1341 media_player_Shutdown,
1344 static HRESULT WINAPI media_player_propstore_QueryInterface(IPropertyStore *iface,
1345 REFIID riid, void **obj)
1347 struct media_player *player = impl_from_IPropertyStore(iface);
1348 return IMFPMediaPlayer_QueryInterface(&player->IMFPMediaPlayer_iface, riid, obj);
1351 static ULONG WINAPI media_player_propstore_AddRef(IPropertyStore *iface)
1353 struct media_player *player = impl_from_IPropertyStore(iface);
1354 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1357 static ULONG WINAPI media_player_propstore_Release(IPropertyStore *iface)
1359 struct media_player *player = impl_from_IPropertyStore(iface);
1360 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1363 static HRESULT WINAPI media_player_propstore_GetCount(IPropertyStore *iface, DWORD *count)
1365 struct media_player *player = impl_from_IPropertyStore(iface);
1367 TRACE("%p, %p.\n", iface, count);
1369 return IPropertyStore_GetCount(player->propstore, count);
1372 static HRESULT WINAPI media_player_propstore_GetAt(IPropertyStore *iface, DWORD prop, PROPERTYKEY *key)
1374 struct media_player *player = impl_from_IPropertyStore(iface);
1376 TRACE("%p, %u, %p.\n", iface, prop, key);
1378 return IPropertyStore_GetAt(player->propstore, prop, key);
1381 static HRESULT WINAPI media_player_propstore_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *value)
1383 struct media_player *player = impl_from_IPropertyStore(iface);
1385 TRACE("%p, %p, %p.\n", iface, key, value);
1387 return IPropertyStore_GetValue(player->propstore, key, value);
1390 static HRESULT WINAPI media_player_propstore_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT value)
1392 struct media_player *player = impl_from_IPropertyStore(iface);
1394 TRACE("%p, %p, %p.\n", iface, key, value);
1396 return IPropertyStore_SetValue(player->propstore, key, value);
1399 static HRESULT WINAPI media_player_propstore_Commit(IPropertyStore *iface)
1401 struct media_player *player = impl_from_IPropertyStore(iface);
1403 TRACE("%p.\n", iface);
1405 return IPropertyStore_Commit(player->propstore);
1408 static const IPropertyStoreVtbl media_player_propstore_vtbl =
1410 media_player_propstore_QueryInterface,
1411 media_player_propstore_AddRef,
1412 media_player_propstore_Release,
1413 media_player_propstore_GetCount,
1414 media_player_propstore_GetAt,
1415 media_player_propstore_GetValue,
1416 media_player_propstore_SetValue,
1417 media_player_propstore_Commit,
1420 static HRESULT WINAPI media_player_callback_QueryInterface(IMFAsyncCallback *iface,
1421 REFIID riid, void **obj)
1423 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
1424 IsEqualIID(riid, &IID_IUnknown))
1426 *obj = iface;
1427 IMFAsyncCallback_AddRef(iface);
1428 return S_OK;
1431 *obj = NULL;
1432 return E_NOINTERFACE;
1435 static ULONG WINAPI media_player_resolver_callback_AddRef(IMFAsyncCallback *iface)
1437 struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
1438 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1441 static ULONG WINAPI media_player_resolver_callback_Release(IMFAsyncCallback *iface)
1443 struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
1444 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1447 static HRESULT WINAPI media_player_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags,
1448 DWORD *queue)
1450 return E_NOTIMPL;
1453 static HRESULT WINAPI media_player_resolver_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1455 struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
1456 struct media_event *event;
1457 IUnknown *object, *state;
1458 MF_OBJECT_TYPE obj_type;
1459 struct media_item *item;
1460 HRESULT hr;
1462 if (FAILED(IMFAsyncResult_GetState(result, &state)))
1463 return S_OK;
1465 item = impl_from_IMFPMediaItem((IMFPMediaItem *)state);
1467 if (item->object)
1469 if (FAILED(hr = IUnknown_QueryInterface(item->object, &IID_IMFMediaSource, (void **)&object)))
1470 hr = IMFSourceResolver_EndCreateObjectFromByteStream(player->resolver, result, &obj_type, &object);
1472 else
1473 hr = IMFSourceResolver_EndCreateObjectFromURL(player->resolver, result, &obj_type, &object);
1475 if (SUCCEEDED(hr))
1477 hr = media_item_set_source(item, object);
1478 IUnknown_Release(object);
1481 if (FAILED(hr))
1482 WARN("Failed to set media source, hr %#x.\n", hr);
1484 if (FAILED(media_event_create(player, MFP_EVENT_TYPE_MEDIAITEM_CREATED, hr,
1485 &item->IMFPMediaItem_iface, &event)))
1487 WARN("Failed to create event object.\n");
1488 IUnknown_Release(state);
1489 return S_OK;
1491 event->u.item_created.dwUserData = item->user_data;
1493 media_player_queue_event(player, event);
1495 IUnknown_Release(&event->IUnknown_iface);
1496 IUnknown_Release(state);
1498 return S_OK;
1501 static const IMFAsyncCallbackVtbl media_player_resolver_callback_vtbl =
1503 media_player_callback_QueryInterface,
1504 media_player_resolver_callback_AddRef,
1505 media_player_resolver_callback_Release,
1506 media_player_callback_GetParameters,
1507 media_player_resolver_callback_Invoke,
1510 static ULONG WINAPI media_player_events_callback_AddRef(IMFAsyncCallback *iface)
1512 struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
1513 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1516 static ULONG WINAPI media_player_events_callback_Release(IMFAsyncCallback *iface)
1518 struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
1519 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1522 static HRESULT WINAPI media_player_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1524 struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
1525 struct media_event *event;
1526 IUnknown *state;
1528 if (FAILED(IMFAsyncResult_GetState(result, &state)))
1529 return S_OK;
1531 event = impl_event_from_IUnknown(state);
1533 if (player->callback)
1534 IMFPMediaPlayerCallback_OnMediaPlayerEvent(player->callback, &event->u.header);
1536 IUnknown_Release(state);
1538 return S_OK;
1541 static const IMFAsyncCallbackVtbl media_player_events_callback_vtbl =
1543 media_player_callback_QueryInterface,
1544 media_player_events_callback_AddRef,
1545 media_player_events_callback_Release,
1546 media_player_callback_GetParameters,
1547 media_player_events_callback_Invoke,
1550 static ULONG WINAPI media_player_session_events_callback_AddRef(IMFAsyncCallback *iface)
1552 struct media_player *player = impl_from_session_events_IMFAsyncCallback(iface);
1553 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1556 static ULONG WINAPI media_player_session_events_callback_Release(IMFAsyncCallback *iface)
1558 struct media_player *player = impl_from_session_events_IMFAsyncCallback(iface);
1559 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1562 static void media_player_change_state(struct media_player *player, MFP_MEDIAPLAYER_STATE state,
1563 HRESULT event_status, struct media_event **event)
1565 MFP_EVENT_TYPE event_type;
1567 EnterCriticalSection(&player->cs);
1569 if (state == MFP_MEDIAPLAYER_STATE_PLAYING)
1570 event_type = MFP_EVENT_TYPE_PLAY;
1571 else if (state == MFP_MEDIAPLAYER_STATE_PAUSED)
1572 event_type = MFP_EVENT_TYPE_PAUSE;
1573 else
1574 event_type = MFP_EVENT_TYPE_STOP;
1576 media_player_set_state(player, state);
1577 media_event_create(player, event_type, event_status, player->item, event);
1579 LeaveCriticalSection(&player->cs);
1582 static void media_player_set_item(struct media_player *player, IMFTopology *topology, HRESULT event_status,
1583 struct media_event **event)
1585 IMFPMediaItem *item;
1587 if (FAILED(IMFTopology_GetUnknown(topology, &_MF_TOPO_MEDIA_ITEM, &IID_IMFPMediaItem, (void **)&item)))
1588 return;
1590 EnterCriticalSection(&player->cs);
1592 if (player->item)
1593 IMFPMediaItem_Release(player->item);
1594 player->item = item;
1595 IMFPMediaItem_AddRef(player->item);
1597 media_event_create(player, MFP_EVENT_TYPE_MEDIAITEM_SET, event_status, item, event);
1599 LeaveCriticalSection(&player->cs);
1601 IMFPMediaItem_Release(item);
1604 static void media_player_clear_item(struct media_player *player, HRESULT event_status,
1605 struct media_event **event)
1607 IMFPMediaItem *item;
1609 EnterCriticalSection(&player->cs);
1611 item = player->item;
1612 player->item = NULL;
1614 media_event_create(player, MFP_EVENT_TYPE_MEDIAITEM_SET, event_status, item, event);
1616 LeaveCriticalSection(&player->cs);
1619 static void media_player_create_forward_event(struct media_player *player, HRESULT event_status, IMFMediaEvent *session_event,
1620 struct media_event **event)
1622 EnterCriticalSection(&player->cs);
1624 if (SUCCEEDED(media_event_create(player, MFP_EVENT_TYPE_MF, event_status, player->item, event)))
1626 IMFMediaEvent_GetType(session_event, &(*event)->u.event.MFEventType);
1627 (*event)->u.event.pMFMediaEvent = session_event;
1628 IMFMediaEvent_AddRef((*event)->u.event.pMFMediaEvent);
1631 LeaveCriticalSection(&player->cs);
1634 static void media_player_create_playback_ended_event(struct media_player *player, HRESULT event_status,
1635 struct media_event **event)
1637 EnterCriticalSection(&player->cs);
1639 if (SUCCEEDED(media_event_create(player, MFP_EVENT_TYPE_PLAYBACK_ENDED, event_status, player->item, event)))
1641 if (player->item)
1642 IMFPMediaItem_Release(player->item);
1643 player->item = NULL;
1646 LeaveCriticalSection(&player->cs);
1649 static HRESULT WINAPI media_player_session_events_callback_Invoke(IMFAsyncCallback *iface,
1650 IMFAsyncResult *result)
1652 struct media_player *player = impl_from_session_events_IMFAsyncCallback(iface);
1653 MediaEventType session_event_type = MEUnknown;
1654 struct media_event *event = NULL;
1655 IMFMediaEvent *session_event;
1656 MFP_MEDIAPLAYER_STATE state;
1657 HRESULT hr, event_status;
1658 IMFPMediaItem *item = NULL;
1659 IMFTopology *topology;
1660 unsigned int status;
1661 PROPVARIANT value;
1663 if (FAILED(hr = IMFMediaSession_EndGetEvent(player->session, result, &session_event)))
1664 return S_OK;
1666 IMFMediaEvent_GetType(session_event, &session_event_type);
1667 IMFMediaEvent_GetStatus(session_event, &event_status);
1669 switch (session_event_type)
1671 case MESessionStarted:
1672 case MESessionStopped:
1673 case MESessionPaused:
1675 if (session_event_type == MESessionStarted)
1676 state = MFP_MEDIAPLAYER_STATE_PLAYING;
1677 else if (session_event_type == MESessionPaused)
1678 state = MFP_MEDIAPLAYER_STATE_PAUSED;
1679 else
1680 state = MFP_MEDIAPLAYER_STATE_STOPPED;
1682 media_player_change_state(player, state, event_status, &event);
1684 break;
1686 case MESessionTopologySet:
1688 value.vt = VT_EMPTY;
1689 if (SUCCEEDED(IMFMediaEvent_GetValue(session_event, &value)))
1691 if (value.vt == VT_EMPTY)
1693 media_player_clear_item(player, event_status, &event);
1695 else if (value.vt == VT_UNKNOWN && value.punkVal &&
1696 SUCCEEDED(IUnknown_QueryInterface(value.punkVal, &IID_IMFTopology, (void **)&topology)))
1698 media_player_set_item(player, topology, event_status, &event);
1699 IMFTopology_Release(topology);
1701 PropVariantClear(&value);
1704 break;
1706 case MESessionTopologyStatus:
1708 if (SUCCEEDED(IMFMediaEvent_GetUINT32(session_event, &MF_EVENT_TOPOLOGY_STATUS, &status)) &&
1709 status == MF_TOPOSTATUS_ENDED)
1711 media_player_create_playback_ended_event(player, event_status, &event);
1714 break;
1716 case MEBufferingStarted:
1717 case MEBufferingStopped:
1718 case MEExtendedType:
1719 case MEReconnectStart:
1720 case MEReconnectEnd:
1721 case MERendererEvent:
1722 case MEStreamSinkFormatChanged:
1724 media_player_create_forward_event(player, event_status, session_event, &event);
1726 break;
1728 case MEError:
1730 media_event_create(player, MFP_EVENT_TYPE_ERROR, event_status, NULL, &event);
1732 break;
1734 default:
1738 if (item)
1739 IMFPMediaItem_Release(item);
1741 if (event)
1743 media_player_queue_event(player, event);
1744 IUnknown_Release(&event->IUnknown_iface);
1747 IMFMediaSession_BeginGetEvent(player->session, &player->session_events_callback, NULL);
1748 IMFMediaEvent_Release(session_event);
1750 return S_OK;
1753 static const IMFAsyncCallbackVtbl media_player_session_events_callback_vtbl =
1755 media_player_callback_QueryInterface,
1756 media_player_session_events_callback_AddRef,
1757 media_player_session_events_callback_Release,
1758 media_player_callback_GetParameters,
1759 media_player_session_events_callback_Invoke,
1762 HRESULT WINAPI MFPCreateMediaPlayer(const WCHAR *url, BOOL start_playback, MFP_CREATION_OPTIONS options,
1763 IMFPMediaPlayerCallback *callback, HWND window, IMFPMediaPlayer **player)
1765 struct media_player *object;
1766 HRESULT hr;
1768 TRACE("%s, %d, %#x, %p, %p, %p.\n", debugstr_w(url), start_playback, options, callback, window, player);
1770 if (!(object = calloc(1, sizeof(*object))))
1771 return E_OUTOFMEMORY;
1773 platform_startup();
1775 object->IMFPMediaPlayer_iface.lpVtbl = &media_player_vtbl;
1776 object->IPropertyStore_iface.lpVtbl = &media_player_propstore_vtbl;
1777 object->resolver_callback.lpVtbl = &media_player_resolver_callback_vtbl;
1778 object->events_callback.lpVtbl = &media_player_events_callback_vtbl;
1779 object->session_events_callback.lpVtbl = &media_player_session_events_callback_vtbl;
1780 object->refcount = 1;
1781 object->callback = callback;
1782 if (object->callback)
1783 IMFPMediaPlayerCallback_AddRef(object->callback);
1784 object->options = options;
1785 object->output_window = window;
1786 InitializeCriticalSection(&object->cs);
1787 if (FAILED(hr = CreatePropertyStore(&object->propstore)))
1788 goto failed;
1789 if (FAILED(hr = MFCreateSourceResolver(&object->resolver)))
1790 goto failed;
1791 if (FAILED(hr = MFCreateMediaSession(NULL, &object->session)))
1792 goto failed;
1793 if (FAILED(hr = IMFMediaSession_BeginGetEvent(object->session, &object->session_events_callback, NULL)))
1794 goto failed;
1795 if (!(object->options & MFP_OPTION_FREE_THREADED_CALLBACK))
1797 object->event_window = CreateWindowW(eventclassW, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE,
1798 0, mfplay_instance, NULL);
1801 *player = &object->IMFPMediaPlayer_iface;
1803 return S_OK;
1805 failed:
1807 IMFPMediaPlayer_Release(&object->IMFPMediaPlayer_iface);
1809 return hr;
1812 static void media_player_register_window_class(void)
1814 WNDCLASSW cls = { 0 };
1816 cls.lpfnWndProc = media_player_event_proc;
1817 cls.hInstance = mfplay_instance;
1818 cls.lpszClassName = eventclassW;
1820 RegisterClassW(&cls);
1823 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
1825 switch (reason)
1827 case DLL_PROCESS_ATTACH:
1828 mfplay_instance = instance;
1829 DisableThreadLibraryCalls(instance);
1830 media_player_register_window_class();
1831 break;
1832 case DLL_PROCESS_DETACH:
1833 if (reserved) break;
1834 UnregisterClassW(eventclassW, instance);
1835 break;
1838 return TRUE;