winex11: Use NtUserBuildHwndList for has_owned_popup implementation.
[wine.git] / dlls / mfplay / player.c
blob7d9a4da8649bd15190e6008be3fadb03ece3cbf7
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 static inline const char *debugstr_normalized_rect(const MFVideoNormalizedRect *rect)
58 if (!rect) return "(null)";
59 return wine_dbg_sprintf("(%.8e,%.8e)-(%.8e,%.8e)", rect->left, rect->top, rect->right, rect->bottom);
62 struct media_player;
64 enum media_item_flags
66 MEDIA_ITEM_SOURCE_NEEDS_SHUTDOWN = 0x1,
69 struct media_item
71 IMFPMediaItem IMFPMediaItem_iface;
72 LONG refcount;
73 struct media_player *player;
74 IMFMediaSource *source;
75 IMFPresentationDescriptor *pd;
76 DWORD_PTR user_data;
77 WCHAR *url;
78 IUnknown *object;
79 LONGLONG start_position;
80 LONGLONG stop_position;
81 unsigned int flags;
84 struct media_player
86 IMFPMediaPlayer IMFPMediaPlayer_iface;
87 IPropertyStore IPropertyStore_iface;
88 IMFAsyncCallback resolver_callback;
89 IMFAsyncCallback events_callback;
90 IMFAsyncCallback session_events_callback;
91 LONG refcount;
92 IMFPMediaPlayerCallback *callback;
93 IPropertyStore *propstore;
94 IMFSourceResolver *resolver;
95 IMFMediaSession *session;
96 IMFPMediaItem *item;
97 MFP_CREATION_OPTIONS options;
98 MFP_MEDIAPLAYER_STATE state;
99 HWND event_window;
100 HWND output_window;
101 CRITICAL_SECTION cs;
104 struct generic_event
106 MFP_EVENT_HEADER header;
107 IMFPMediaItem *item;
110 struct media_event
112 IUnknown IUnknown_iface;
113 LONG refcount;
114 union
116 MFP_EVENT_HEADER header;
117 struct generic_event generic;
118 MFP_PLAY_EVENT play;
119 MFP_PAUSE_EVENT pause;
120 MFP_STOP_EVENT stop;
121 MFP_POSITION_SET_EVENT position_set;
122 MFP_RATE_SET_EVENT rate_set;
123 MFP_MEDIAITEM_CREATED_EVENT item_created;
124 MFP_MEDIAITEM_SET_EVENT item_set;
125 MFP_MEDIAITEM_CLEARED_EVENT item_cleared;
126 MFP_MF_EVENT event;
127 MFP_ERROR_EVENT error;
128 MFP_PLAYBACK_ENDED_EVENT ended;
129 MFP_ACQUIRE_USER_CREDENTIAL_EVENT acquire_creds;
130 } u;
133 static struct media_player *impl_from_IMFPMediaPlayer(IMFPMediaPlayer *iface)
135 return CONTAINING_RECORD(iface, struct media_player, IMFPMediaPlayer_iface);
138 static struct media_player *impl_from_IPropertyStore(IPropertyStore *iface)
140 return CONTAINING_RECORD(iface, struct media_player, IPropertyStore_iface);
143 static struct media_player *impl_from_resolver_IMFAsyncCallback(IMFAsyncCallback *iface)
145 return CONTAINING_RECORD(iface, struct media_player, resolver_callback);
148 static struct media_player *impl_from_events_IMFAsyncCallback(IMFAsyncCallback *iface)
150 return CONTAINING_RECORD(iface, struct media_player, events_callback);
153 static struct media_player *impl_from_session_events_IMFAsyncCallback(IMFAsyncCallback *iface)
155 return CONTAINING_RECORD(iface, struct media_player, session_events_callback);
158 static struct media_item *impl_from_IMFPMediaItem(IMFPMediaItem *iface)
160 return CONTAINING_RECORD(iface, struct media_item, IMFPMediaItem_iface);
163 static struct media_event *impl_event_from_IUnknown(IUnknown *iface)
165 return CONTAINING_RECORD(iface, struct media_event, IUnknown_iface);
168 static HRESULT WINAPI media_event_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
170 if (IsEqualIID(riid, &IID_IUnknown))
172 *obj = iface;
173 IUnknown_AddRef(iface);
174 return S_OK;
177 *obj = NULL;
178 return E_NOINTERFACE;
181 static ULONG WINAPI media_event_AddRef(IUnknown *iface)
183 struct media_event *event = impl_event_from_IUnknown(iface);
184 ULONG refcount = InterlockedIncrement(&event->refcount);
186 TRACE("%p, refcount %lu.\n", iface, refcount);
188 return refcount;
191 static ULONG WINAPI media_event_Release(IUnknown *iface)
193 struct media_event *event = impl_event_from_IUnknown(iface);
194 ULONG refcount = InterlockedDecrement(&event->refcount);
196 TRACE("%p, refcount %lu.\n", iface, refcount);
198 if (!refcount)
200 if (event->u.header.pMediaPlayer)
201 IMFPMediaPlayer_Release(event->u.header.pMediaPlayer);
202 if (event->u.header.pPropertyStore)
203 IPropertyStore_Release(event->u.header.pPropertyStore);
205 switch (event->u.header.eEventType)
207 /* Most types share same layout. */
208 case MFP_EVENT_TYPE_PLAY:
209 case MFP_EVENT_TYPE_PAUSE:
210 case MFP_EVENT_TYPE_STOP:
211 case MFP_EVENT_TYPE_POSITION_SET:
212 case MFP_EVENT_TYPE_RATE_SET:
213 case MFP_EVENT_TYPE_MEDIAITEM_CREATED:
214 case MFP_EVENT_TYPE_MEDIAITEM_SET:
215 case MFP_EVENT_TYPE_FRAME_STEP:
216 case MFP_EVENT_TYPE_MEDIAITEM_CLEARED:
217 case MFP_EVENT_TYPE_PLAYBACK_ENDED:
218 if (event->u.generic.item)
219 IMFPMediaItem_Release(event->u.generic.item);
220 break;
221 case MFP_EVENT_TYPE_MF:
222 if (event->u.event.pMFMediaEvent)
223 IMFMediaEvent_Release(event->u.event.pMFMediaEvent);
224 if (event->u.event.pMediaItem)
225 IMFPMediaItem_Release(event->u.event.pMediaItem);
226 break;
227 default:
228 FIXME("Unsupported event %u.\n", event->u.header.eEventType);
229 break;
232 free(event);
235 return refcount;
238 static const IUnknownVtbl media_event_vtbl =
240 media_event_QueryInterface,
241 media_event_AddRef,
242 media_event_Release,
245 static HRESULT media_event_create(struct media_player *player, MFP_EVENT_TYPE event_type,
246 HRESULT hr, IMFPMediaItem *item, struct media_event **event)
248 struct media_event *object;
250 if (!(object = calloc(1, sizeof(*object))))
251 return E_OUTOFMEMORY;
253 object->IUnknown_iface.lpVtbl = &media_event_vtbl;
254 object->refcount = 1;
255 object->u.header.eEventType = event_type;
256 object->u.header.hrEvent = hr;
257 object->u.header.pMediaPlayer = &player->IMFPMediaPlayer_iface;
258 IMFPMediaPlayer_AddRef(object->u.header.pMediaPlayer);
259 object->u.header.eState = player->state;
260 switch (event_type)
262 case MFP_EVENT_TYPE_PLAY:
263 case MFP_EVENT_TYPE_PAUSE:
264 case MFP_EVENT_TYPE_STOP:
265 case MFP_EVENT_TYPE_POSITION_SET:
266 case MFP_EVENT_TYPE_RATE_SET:
267 case MFP_EVENT_TYPE_MEDIAITEM_CREATED:
268 case MFP_EVENT_TYPE_MEDIAITEM_SET:
269 case MFP_EVENT_TYPE_FRAME_STEP:
270 case MFP_EVENT_TYPE_MEDIAITEM_CLEARED:
271 case MFP_EVENT_TYPE_PLAYBACK_ENDED:
272 object->u.generic.item = item;
273 if (object->u.generic.item)
274 IMFPMediaItem_AddRef(object->u.generic.item);
275 break;
276 case MFP_EVENT_TYPE_MF:
277 object->u.event.pMediaItem = item;
278 if (object->u.event.pMediaItem)
279 IMFPMediaItem_AddRef(object->u.event.pMediaItem);
280 break;
281 default:
285 /* FIXME: set properties for some events? */
287 *event = object;
289 return S_OK;
292 static LRESULT WINAPI media_player_event_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
294 struct media_event *event = (void *)lparam;
295 struct media_player *player;
297 if (msg == WM_USER)
299 player = impl_from_IMFPMediaPlayer(event->u.header.pMediaPlayer);
300 if (player->callback)
301 IMFPMediaPlayerCallback_OnMediaPlayerEvent(player->callback, &event->u.header);
302 IUnknown_Release(&event->IUnknown_iface);
303 return 0;
306 return DefWindowProcW(hwnd, msg, wparam, lparam);
309 static void media_player_set_state(struct media_player *player, MFP_MEDIAPLAYER_STATE state)
311 if (player->state != MFP_MEDIAPLAYER_STATE_SHUTDOWN)
313 if (state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
314 IMFMediaSession_Shutdown(player->session);
315 player->state = state;
319 static HRESULT media_item_get_pd(const struct media_item *item, IMFPresentationDescriptor **pd)
321 if (item->player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
322 return MF_E_SHUTDOWN;
324 *pd = item->pd;
325 IMFPresentationDescriptor_AddRef(*pd);
326 return S_OK;
329 static HRESULT WINAPI media_item_QueryInterface(IMFPMediaItem *iface, REFIID riid, void **obj)
331 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
333 if (IsEqualIID(riid, &IID_IMFPMediaItem) ||
334 IsEqualIID(riid, &IID_IUnknown))
336 *obj = iface;
337 IMFPMediaItem_AddRef(iface);
338 return S_OK;
341 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
342 *obj = NULL;
343 return E_NOINTERFACE;
346 static ULONG WINAPI media_item_AddRef(IMFPMediaItem *iface)
348 struct media_item *item = impl_from_IMFPMediaItem(iface);
349 ULONG refcount = InterlockedIncrement(&item->refcount);
351 TRACE("%p, refcount %lu.\n", iface, refcount);
353 return refcount;
356 static ULONG WINAPI media_item_Release(IMFPMediaItem *iface)
358 struct media_item *item = impl_from_IMFPMediaItem(iface);
359 ULONG refcount = InterlockedDecrement(&item->refcount);
361 TRACE("%p, refcount %lu.\n", iface, refcount);
363 if (!refcount)
365 if (item->player)
366 IMFPMediaPlayer_Release(&item->player->IMFPMediaPlayer_iface);
367 if (item->source)
369 if (item->flags & MEDIA_ITEM_SOURCE_NEEDS_SHUTDOWN)
370 IMFMediaSource_Shutdown(item->source);
371 IMFMediaSource_Release(item->source);
373 if (item->pd)
374 IMFPresentationDescriptor_Release(item->pd);
375 if (item->object)
376 IUnknown_Release(item->object);
377 free(item->url);
378 free(item);
381 return refcount;
384 static HRESULT WINAPI media_item_GetMediaPlayer(IMFPMediaItem *iface,
385 IMFPMediaPlayer **player)
387 struct media_item *item = impl_from_IMFPMediaItem(iface);
388 HRESULT hr = S_OK;
390 TRACE("%p, %p.\n", iface, player);
392 EnterCriticalSection(&item->player->cs);
393 if (item->player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
395 hr = MF_E_SHUTDOWN;
396 *player = NULL;
398 else
400 *player = &item->player->IMFPMediaPlayer_iface;
401 IMFPMediaPlayer_AddRef(*player);
403 LeaveCriticalSection(&item->player->cs);
405 return hr;
408 static HRESULT WINAPI media_item_GetURL(IMFPMediaItem *iface, LPWSTR *url)
410 struct media_item *item = impl_from_IMFPMediaItem(iface);
411 HRESULT hr = S_OK;
413 TRACE("%p, %p.\n", iface, url);
415 EnterCriticalSection(&item->player->cs);
416 if (item->player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
417 hr = MF_E_SHUTDOWN;
418 else if (!item->url)
419 hr = MF_E_NOT_FOUND;
420 else
422 if (!(*url = CoTaskMemAlloc((wcslen(item->url) + 1) * sizeof(*item->url))))
423 hr = E_OUTOFMEMORY;
424 if (*url)
425 wcscpy(*url, item->url);
427 LeaveCriticalSection(&item->player->cs);
429 return hr;
432 static HRESULT WINAPI media_item_GetObject(IMFPMediaItem *iface, IUnknown **object)
434 struct media_item *item = impl_from_IMFPMediaItem(iface);
435 HRESULT hr = S_OK;
437 TRACE("%p, %p.\n", iface, object);
439 EnterCriticalSection(&item->player->cs);
440 if (item->player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
441 hr = MF_E_SHUTDOWN;
442 else if (!item->object)
443 hr = MF_E_NOT_FOUND;
444 else
446 *object = item->object;
447 IUnknown_AddRef(*object);
449 LeaveCriticalSection(&item->player->cs);
451 return hr;
454 static HRESULT WINAPI media_item_GetUserData(IMFPMediaItem *iface, DWORD_PTR *user_data)
456 struct media_item *item = impl_from_IMFPMediaItem(iface);
458 TRACE("%p, %p.\n", iface, user_data);
460 *user_data = item->user_data;
462 return S_OK;
465 static HRESULT WINAPI media_item_SetUserData(IMFPMediaItem *iface, DWORD_PTR user_data)
467 struct media_item *item = impl_from_IMFPMediaItem(iface);
469 TRACE("%p, %Ix.\n", iface, user_data);
471 item->user_data = user_data;
473 return S_OK;
476 static HRESULT media_item_set_position(const GUID *format, const PROPVARIANT *position, LARGE_INTEGER *ret)
478 ret->QuadPart = 0;
480 if (format && !IsEqualGUID(format, &MFP_POSITIONTYPE_100NS))
481 return E_INVALIDARG;
483 if ((format != NULL) ^ (position != NULL))
484 return E_POINTER;
486 if (position && position->vt != VT_EMPTY && position->vt != VT_I8)
487 return E_INVALIDARG;
489 if ((!format && !position) || position->vt == VT_EMPTY)
490 return S_OK;
492 if (position->hVal.QuadPart == 0)
493 return MF_E_OUT_OF_RANGE;
495 ret->QuadPart = position->hVal.QuadPart;
497 return S_OK;
500 static void media_item_get_position(LONGLONG value, GUID *format, PROPVARIANT *position)
502 if (!format)
503 return;
505 memcpy(format, &MFP_POSITIONTYPE_100NS, sizeof(*format));
507 if (value)
509 position->vt = VT_I8;
510 position->hVal.QuadPart = value;
514 static HRESULT WINAPI media_item_GetStartStopPosition(IMFPMediaItem *iface, GUID *start_format,
515 PROPVARIANT *start_position, GUID *stop_format, PROPVARIANT *stop_position)
517 struct media_item *item = impl_from_IMFPMediaItem(iface);
519 TRACE("%p, %p, %p, %p, %p.\n", iface, start_format, start_position, stop_format, stop_position);
521 if (start_position)
522 start_position->vt = VT_EMPTY;
523 if (stop_position)
524 stop_position->vt = VT_EMPTY;
526 if (((start_format != NULL) ^ (start_position != NULL)) ||
527 ((stop_format != NULL) ^ (stop_position != NULL)))
529 return E_POINTER;
532 media_item_get_position(item->start_position, start_format, start_position);
533 media_item_get_position(item->stop_position, stop_format, stop_position);
535 return S_OK;
538 static HRESULT WINAPI media_item_SetStartStopPosition(IMFPMediaItem *iface, const GUID *start_format,
539 const PROPVARIANT *start_position, const GUID *stop_format, const PROPVARIANT *stop_position)
541 struct media_item *item = impl_from_IMFPMediaItem(iface);
542 LARGE_INTEGER start, stop;
543 HRESULT hr;
545 TRACE("%p, %s, %p, %s, %p.\n", iface, debugstr_guid(start_format), start_position,
546 debugstr_guid(stop_format), stop_position);
548 hr = media_item_set_position(start_format, start_position, &start);
549 if (SUCCEEDED(hr))
550 hr = media_item_set_position(stop_format, stop_position, &stop);
552 if (FAILED(hr))
553 return hr;
555 if (start.QuadPart > stop.QuadPart)
556 return MF_E_OUT_OF_RANGE;
558 item->start_position = start.QuadPart;
559 item->stop_position = stop.QuadPart;
561 return hr;
564 static HRESULT media_item_get_stream_type(IMFStreamDescriptor *sd, GUID *major)
566 IMFMediaTypeHandler *handler;
567 HRESULT hr;
569 if (SUCCEEDED(hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler)))
571 hr = IMFMediaTypeHandler_GetMajorType(handler, major);
572 IMFMediaTypeHandler_Release(handler);
575 return hr;
578 static HRESULT media_item_has_stream(struct media_item *item, const GUID *major, BOOL *has_stream, BOOL *is_selected)
580 IMFPresentationDescriptor *pd;
581 IMFStreamDescriptor *sd;
582 unsigned int idx = 0;
583 BOOL selected;
584 HRESULT hr;
585 GUID guid;
587 EnterCriticalSection(&item->player->cs);
589 if (SUCCEEDED(hr = media_item_get_pd(item, &pd)))
591 *has_stream = *is_selected = FALSE;
593 while (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, idx++, &selected, &sd)))
595 if (SUCCEEDED(media_item_get_stream_type(sd, &guid)) && IsEqualGUID(&guid, major))
597 *has_stream = TRUE;
598 *is_selected = selected;
601 IMFStreamDescriptor_Release(sd);
603 if (*has_stream && *is_selected)
604 break;
606 IMFPresentationDescriptor_Release(pd);
609 LeaveCriticalSection(&item->player->cs);
611 return hr;
614 static HRESULT WINAPI media_item_HasVideo(IMFPMediaItem *iface, BOOL *has_video, BOOL *selected)
616 struct media_item *item = impl_from_IMFPMediaItem(iface);
618 TRACE("%p, %p, %p.\n", iface, has_video, selected);
620 return media_item_has_stream(item, &MFMediaType_Video, has_video, selected);
623 static HRESULT WINAPI media_item_HasAudio(IMFPMediaItem *iface, BOOL *has_audio, BOOL *selected)
625 struct media_item *item = impl_from_IMFPMediaItem(iface);
627 TRACE("%p, %p, %p.\n", iface, has_audio, selected);
629 return media_item_has_stream(item, &MFMediaType_Audio, has_audio, selected);
632 static HRESULT WINAPI media_item_IsProtected(IMFPMediaItem *iface, BOOL *protected)
634 struct media_item *item = impl_from_IMFPMediaItem(iface);
635 IMFPresentationDescriptor *pd;
636 HRESULT hr;
638 TRACE("%p, %p.\n", iface, protected);
640 if (!protected)
641 return E_POINTER;
643 EnterCriticalSection(&item->player->cs);
644 if (SUCCEEDED(hr = media_item_get_pd(item, &pd)))
646 *protected = (hr = MFRequireProtectedEnvironment(pd)) == S_OK;
647 IMFPresentationDescriptor_Release(pd);
649 LeaveCriticalSection(&item->player->cs);
651 return hr;
654 static HRESULT WINAPI media_item_GetDuration(IMFPMediaItem *iface, REFGUID format, PROPVARIANT *value)
656 struct media_item *item = impl_from_IMFPMediaItem(iface);
657 IMFPresentationDescriptor *pd;
658 HRESULT hr;
660 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), value);
662 EnterCriticalSection(&item->player->cs);
663 if (SUCCEEDED(hr = media_item_get_pd(item, &pd)))
665 hr = IMFPresentationDescriptor_GetItem(pd, &MF_PD_DURATION, value);
666 IMFPresentationDescriptor_Release(pd);
668 LeaveCriticalSection(&item->player->cs);
670 return hr;
673 static HRESULT WINAPI media_item_GetNumberOfStreams(IMFPMediaItem *iface, DWORD *count)
675 struct media_item *item = impl_from_IMFPMediaItem(iface);
676 IMFPresentationDescriptor *pd;
677 HRESULT hr;
679 TRACE("%p, %p.\n", iface, count);
681 EnterCriticalSection(&item->player->cs);
682 if (SUCCEEDED(hr = media_item_get_pd(item, &pd)))
684 hr = IMFPresentationDescriptor_GetStreamDescriptorCount(pd, count);
685 IMFPresentationDescriptor_Release(pd);
687 LeaveCriticalSection(&item->player->cs);
689 return hr;
692 static HRESULT WINAPI media_item_GetStreamSelection(IMFPMediaItem *iface, DWORD index, BOOL *selected)
694 struct media_item *item = impl_from_IMFPMediaItem(iface);
695 IMFPresentationDescriptor *pd;
696 IMFStreamDescriptor *sd;
697 HRESULT hr;
699 TRACE("%p, %lu, %p.\n", iface, index, selected);
701 EnterCriticalSection(&item->player->cs);
702 if (SUCCEEDED(hr = media_item_get_pd(item, &pd)))
704 if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, index, selected, &sd)))
705 IMFStreamDescriptor_Release(sd);
706 IMFPresentationDescriptor_Release(pd);
708 LeaveCriticalSection(&item->player->cs);
710 return hr;
713 static HRESULT WINAPI media_item_SetStreamSelection(IMFPMediaItem *iface, DWORD index, BOOL select)
715 struct media_item *item = impl_from_IMFPMediaItem(iface);
716 IMFPresentationDescriptor *pd;
717 HRESULT hr;
719 TRACE("%p, %lu, %d.\n", iface, index, select);
721 EnterCriticalSection(&item->player->cs);
722 if (SUCCEEDED(hr = media_item_get_pd(item, &pd)))
724 hr = select ? IMFPresentationDescriptor_SelectStream(pd, index) :
725 IMFPresentationDescriptor_DeselectStream(pd, index);
726 IMFPresentationDescriptor_Release(pd);
728 LeaveCriticalSection(&item->player->cs);
730 return hr;
733 static HRESULT WINAPI media_item_GetStreamAttribute(IMFPMediaItem *iface, DWORD index, REFGUID key,
734 PROPVARIANT *value)
736 struct media_item *item = impl_from_IMFPMediaItem(iface);
737 IMFPresentationDescriptor *pd;
738 IMFStreamDescriptor *sd;
739 BOOL selected;
740 HRESULT hr;
742 TRACE("%p, %lu, %s, %p.\n", iface, index, debugstr_guid(key), value);
744 EnterCriticalSection(&item->player->cs);
745 if (SUCCEEDED(hr = media_item_get_pd(item, &pd)))
747 if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, index, &selected, &sd)))
749 hr = IMFStreamDescriptor_GetItem(sd, key, value);
750 IMFStreamDescriptor_Release(sd);
752 IMFPresentationDescriptor_Release(pd);
754 LeaveCriticalSection(&item->player->cs);
756 return hr;
759 static HRESULT WINAPI media_item_GetPresentationAttribute(IMFPMediaItem *iface, REFGUID key,
760 PROPVARIANT *value)
762 struct media_item *item = impl_from_IMFPMediaItem(iface);
763 IMFPresentationDescriptor *pd;
764 HRESULT hr;
766 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
768 EnterCriticalSection(&item->player->cs);
769 if (SUCCEEDED(hr = media_item_get_pd(item, &pd)))
771 hr = IMFPresentationDescriptor_GetItem(pd, key, value);
772 IMFPresentationDescriptor_Release(pd);
774 LeaveCriticalSection(&item->player->cs);
776 return hr;
779 static HRESULT WINAPI media_item_GetCharacteristics(IMFPMediaItem *iface, MFP_MEDIAITEM_CHARACTERISTICS *flags)
781 struct media_item *item = impl_from_IMFPMediaItem(iface);
782 DWORD value = 0;
783 HRESULT hr;
785 TRACE("%p, %p.\n", iface, flags);
787 *flags = 0;
789 EnterCriticalSection(&item->player->cs);
790 if (item->player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
791 hr = MF_E_SHUTDOWN;
792 else
794 if (SUCCEEDED(hr = IMFMediaSource_GetCharacteristics(item->source, &value)))
796 *flags = value & (MFP_MEDIAITEM_IS_LIVE | MFP_MEDIAITEM_CAN_SEEK
797 | MFP_MEDIAITEM_CAN_PAUSE | MFP_MEDIAITEM_HAS_SLOW_SEEK);
800 LeaveCriticalSection(&item->player->cs);
802 return hr;
805 static HRESULT WINAPI media_item_SetStreamSink(IMFPMediaItem *iface, DWORD index, IUnknown *sink)
807 struct media_item *item = impl_from_IMFPMediaItem(iface);
808 IMFStreamDescriptor *sd;
809 IUnknown *sink_object;
810 BOOL selected;
811 HRESULT hr;
813 TRACE("%p, %lu, %p.\n", iface, index, sink);
815 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, index, &selected, &sd)))
816 return hr;
818 if (sink)
820 if (FAILED(hr = IUnknown_QueryInterface(sink, &IID_IMFStreamSink, (void **)&sink_object)))
821 hr = IUnknown_QueryInterface(sink, &IID_IMFActivate, (void **)&sink_object);
823 if (sink_object)
825 hr = IMFStreamDescriptor_SetUnknown(sd, &_MF_CUSTOM_SINK, sink_object);
826 IUnknown_Release(sink_object);
829 else
830 IMFStreamDescriptor_DeleteItem(sd, &_MF_CUSTOM_SINK);
832 IMFStreamDescriptor_Release(sd);
834 return hr;
837 static HRESULT WINAPI media_item_GetMetadata(IMFPMediaItem *iface, IPropertyStore **metadata)
839 struct media_item *item = impl_from_IMFPMediaItem(iface);
841 TRACE("%p, %p.\n", iface, metadata);
843 return MFGetService((IUnknown *)item->source, &MF_PROPERTY_HANDLER_SERVICE,
844 &IID_IPropertyStore, (void **)metadata);
847 static const IMFPMediaItemVtbl media_item_vtbl =
849 media_item_QueryInterface,
850 media_item_AddRef,
851 media_item_Release,
852 media_item_GetMediaPlayer,
853 media_item_GetURL,
854 media_item_GetObject,
855 media_item_GetUserData,
856 media_item_SetUserData,
857 media_item_GetStartStopPosition,
858 media_item_SetStartStopPosition,
859 media_item_HasVideo,
860 media_item_HasAudio,
861 media_item_IsProtected,
862 media_item_GetDuration,
863 media_item_GetNumberOfStreams,
864 media_item_GetStreamSelection,
865 media_item_SetStreamSelection,
866 media_item_GetStreamAttribute,
867 media_item_GetPresentationAttribute,
868 media_item_GetCharacteristics,
869 media_item_SetStreamSink,
870 media_item_GetMetadata,
873 static struct media_item *unsafe_impl_from_IMFPMediaItem(IMFPMediaItem *iface)
875 if (!iface)
876 return NULL;
877 assert(iface->lpVtbl == (IMFPMediaItemVtbl *)&media_item_vtbl);
878 return CONTAINING_RECORD(iface, struct media_item, IMFPMediaItem_iface);
881 static HRESULT create_media_item(struct media_player *player, DWORD_PTR user_data, struct media_item **item)
883 struct media_item *object;
885 if (!(object = calloc(1, sizeof(*object))))
886 return E_OUTOFMEMORY;
888 object->IMFPMediaItem_iface.lpVtbl = &media_item_vtbl;
889 object->refcount = 1;
890 object->user_data = user_data;
891 object->player = player;
892 IMFPMediaPlayer_AddRef(&object->player->IMFPMediaPlayer_iface);
894 *item = object;
896 return S_OK;
899 static HRESULT media_item_set_source(struct media_item *item, IUnknown *object)
901 IMFPresentationDescriptor *pd;
902 IMFMediaSource *source;
903 HRESULT hr;
905 if (FAILED(hr = IUnknown_QueryInterface(object, &IID_IMFMediaSource, (void **)&source)))
906 return hr;
908 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd)))
910 WARN("Failed to get presentation descriptor, hr %#lx.\n", hr);
911 IMFMediaSource_Release(source);
912 return hr;
915 item->source = source;
916 item->pd = pd;
918 return hr;
921 static void media_player_queue_event(struct media_player *player, struct media_event *event)
923 if (player->options & MFP_OPTION_FREE_THREADED_CALLBACK)
925 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, &player->events_callback, &event->IUnknown_iface);
927 else
929 IUnknown_AddRef(&event->IUnknown_iface);
930 PostMessageW(player->event_window, WM_USER, 0, (LPARAM)event);
934 static HRESULT WINAPI media_player_QueryInterface(IMFPMediaPlayer *iface, REFIID riid, void **obj)
936 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
938 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
940 if (IsEqualIID(riid, &IID_IMFPMediaPlayer) ||
941 IsEqualIID(riid, &IID_IUnknown))
943 *obj = &player->IMFPMediaPlayer_iface;
945 else if (IsEqualIID(riid, &IID_IPropertyStore))
947 *obj = &player->IPropertyStore_iface;
949 else
951 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
952 *obj = NULL;
954 return E_NOINTERFACE;
957 IUnknown_AddRef((IUnknown *)*obj);
958 return S_OK;
961 static ULONG WINAPI media_player_AddRef(IMFPMediaPlayer *iface)
963 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
964 ULONG refcount = InterlockedIncrement(&player->refcount);
966 TRACE("%p, refcount %lu.\n", iface, refcount);
968 return refcount;
971 static ULONG WINAPI media_player_Release(IMFPMediaPlayer *iface)
973 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
974 ULONG refcount = InterlockedDecrement(&player->refcount);
976 TRACE("%p, refcount %lu.\n", iface, refcount);
978 if (!refcount)
980 if (player->callback)
981 IMFPMediaPlayerCallback_Release(player->callback);
982 if (player->propstore)
983 IPropertyStore_Release(player->propstore);
984 if (player->resolver)
985 IMFSourceResolver_Release(player->resolver);
986 if (player->session)
987 IMFMediaSession_Release(player->session);
988 DestroyWindow(player->event_window);
989 DeleteCriticalSection(&player->cs);
990 free(player);
992 platform_shutdown();
995 return refcount;
998 static HRESULT WINAPI media_player_Play(IMFPMediaPlayer *iface)
1000 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1001 PROPVARIANT pos;
1003 TRACE("%p.\n", iface);
1005 pos.vt = VT_EMPTY;
1006 return IMFMediaSession_Start(player->session, &GUID_NULL, &pos);
1009 static HRESULT WINAPI media_player_Pause(IMFPMediaPlayer *iface)
1011 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1013 TRACE("%p.\n", iface);
1015 return IMFMediaSession_Pause(player->session);
1018 static HRESULT WINAPI media_player_Stop(IMFPMediaPlayer *iface)
1020 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1022 TRACE("%p.\n", iface);
1024 return IMFMediaSession_Stop(player->session);
1027 static HRESULT WINAPI media_player_FrameStep(IMFPMediaPlayer *iface)
1029 FIXME("%p.\n", iface);
1031 return E_NOTIMPL;
1034 static HRESULT WINAPI media_player_SetPosition(IMFPMediaPlayer *iface, REFGUID postype, const PROPVARIANT *position)
1036 FIXME("%p, %s, %p.\n", iface, debugstr_guid(postype), position);
1038 return E_NOTIMPL;
1041 static HRESULT WINAPI media_player_GetPosition(IMFPMediaPlayer *iface, REFGUID postype, PROPVARIANT *position)
1043 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1044 IMFPresentationClock *presentation_clock;
1045 IMFClock *clock;
1046 HRESULT hr;
1048 TRACE("%p, %s, %p.\n", iface, debugstr_guid(postype), position);
1050 if (!position)
1051 return E_POINTER;
1053 if (!IsEqualGUID(postype, &MFP_POSITIONTYPE_100NS))
1054 return E_INVALIDARG;
1056 EnterCriticalSection(&player->cs);
1057 if (player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
1058 hr = MF_E_SHUTDOWN;
1059 else if (!player->item)
1060 hr = MF_E_INVALIDREQUEST;
1061 else
1063 if (SUCCEEDED(hr = IMFMediaSession_GetClock(player->session, &clock)))
1065 if (SUCCEEDED(hr = IMFClock_QueryInterface(clock, &IID_IMFPresentationClock, (void **)&presentation_clock)))
1067 position->vt = VT_UI8;
1068 hr = IMFPresentationClock_GetTime(presentation_clock, (MFTIME *)&position->uhVal.QuadPart);
1069 IMFPresentationClock_Release(presentation_clock);
1071 IMFClock_Release(clock);
1074 LeaveCriticalSection(&player->cs);
1076 return hr;
1079 static HRESULT WINAPI media_player_GetDuration(IMFPMediaPlayer *iface, REFGUID postype, PROPVARIANT *duration)
1081 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1082 HRESULT hr;
1084 TRACE("%p, %s, %p.\n", iface, debugstr_guid(postype), duration);
1086 if (!duration)
1087 return E_POINTER;
1089 if (!IsEqualGUID(postype, &MFP_POSITIONTYPE_100NS))
1090 return E_INVALIDARG;
1092 EnterCriticalSection(&player->cs);
1093 if (player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
1094 hr = MF_E_SHUTDOWN;
1095 else if (!player->item)
1096 hr = MF_E_INVALIDREQUEST;
1097 else
1098 /* FIXME: use start/stop markers for resulting duration */
1099 hr = IMFPMediaItem_GetDuration(player->item, postype, duration);
1100 LeaveCriticalSection(&player->cs);
1102 return hr;
1105 static HRESULT WINAPI media_player_SetRate(IMFPMediaPlayer *iface, float rate)
1107 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1108 IMFRateControl *rate_control;
1109 HRESULT hr;
1111 TRACE("%p, %f.\n", iface, rate);
1113 if (rate == 0.0f)
1114 return MF_E_OUT_OF_RANGE;
1116 if (SUCCEEDED(hr = MFGetService((IUnknown *)player->session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateControl,
1117 (void **)&rate_control)))
1119 hr = IMFRateControl_SetRate(rate_control, FALSE, rate);
1120 IMFRateControl_Release(rate_control);
1123 return hr;
1126 static HRESULT WINAPI media_player_GetRate(IMFPMediaPlayer *iface, float *rate)
1128 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1129 IMFRateControl *rate_control;
1130 HRESULT hr;
1132 TRACE("%p, %p.\n", iface, rate);
1134 if (!rate)
1135 return E_POINTER;
1137 if (SUCCEEDED(hr = MFGetService((IUnknown *)player->session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateControl,
1138 (void **)&rate_control)))
1140 hr = IMFRateControl_GetRate(rate_control, NULL, rate);
1141 IMFRateControl_Release(rate_control);
1144 return hr;
1147 static HRESULT WINAPI media_player_GetSupportedRates(IMFPMediaPlayer *iface, BOOL forward,
1148 float *slowest_rate, float *fastest_rate)
1150 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1151 IMFRateSupport *rs;
1152 HRESULT hr;
1154 TRACE("%p, %d, %p, %p.\n", iface, forward, slowest_rate, fastest_rate);
1156 if (SUCCEEDED(hr = MFGetService((IUnknown *)player->session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rs)))
1158 if (SUCCEEDED(hr = IMFRateSupport_GetSlowestRate(rs, forward ? MFRATE_FORWARD : MFRATE_REVERSE, FALSE, slowest_rate)))
1159 hr = IMFRateSupport_GetFastestRate(rs, forward ? MFRATE_FORWARD : MFRATE_REVERSE, FALSE, fastest_rate);
1160 IMFRateSupport_Release(rs);
1163 return hr;
1166 static HRESULT WINAPI media_player_GetState(IMFPMediaPlayer *iface, MFP_MEDIAPLAYER_STATE *state)
1168 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1170 TRACE("%p, %p.\n", iface, state);
1172 *state = player->state;
1174 return S_OK;
1177 static HRESULT media_player_create_item_from_url(struct media_player *player,
1178 const WCHAR *url, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **ret)
1180 struct media_item *item;
1181 MF_OBJECT_TYPE obj_type;
1182 IUnknown *object;
1183 HRESULT hr;
1185 if (sync && !ret)
1186 return E_POINTER;
1188 if (!sync && !player->callback)
1190 WARN("Asynchronous item creation is not supported without user callback.\n");
1191 return MF_E_INVALIDREQUEST;
1194 if (FAILED(hr = create_media_item(player, user_data, &item)))
1195 return hr;
1197 if (url && !(item->url = wcsdup(url)))
1199 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
1200 return E_OUTOFMEMORY;
1202 item->flags |= MEDIA_ITEM_SOURCE_NEEDS_SHUTDOWN;
1204 if (sync)
1206 *ret = NULL;
1208 if (SUCCEEDED(hr = IMFSourceResolver_CreateObjectFromURL(player->resolver, url, MF_RESOLUTION_MEDIASOURCE
1209 | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE, player->propstore, &obj_type, &object)))
1211 hr = media_item_set_source(item, object);
1212 IUnknown_Release(object);
1215 if (SUCCEEDED(hr))
1217 *ret = &item->IMFPMediaItem_iface;
1218 IMFPMediaItem_AddRef(*ret);
1221 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
1223 else
1225 if (ret) *ret = NULL;
1227 hr = IMFSourceResolver_BeginCreateObjectFromURL(player->resolver, url, MF_RESOLUTION_MEDIASOURCE
1228 | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE, player->propstore, NULL,
1229 &player->resolver_callback, (IUnknown *)&item->IMFPMediaItem_iface);
1231 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
1234 return hr;
1237 static HRESULT WINAPI media_player_CreateMediaItemFromURL(IMFPMediaPlayer *iface,
1238 const WCHAR *url, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **item)
1240 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1241 HRESULT hr;
1243 TRACE("%p, %s, %d, %Ix, %p.\n", iface, debugstr_w(url), sync, user_data, item);
1245 EnterCriticalSection(&player->cs);
1246 if (player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
1247 hr = MF_E_SHUTDOWN;
1248 else
1249 hr = media_player_create_item_from_url(player, url, sync, user_data, item);
1250 LeaveCriticalSection(&player->cs);
1252 return hr;
1255 static HRESULT media_player_create_item_from_object(struct media_player *player,
1256 IUnknown *object, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **ret)
1258 IMFMediaSource *source = NULL;
1259 IMFByteStream *stream = NULL;
1260 struct media_item *item;
1261 MF_OBJECT_TYPE obj_type;
1262 HRESULT hr;
1264 *ret = NULL;
1266 if (FAILED(hr = create_media_item(player, user_data, &item)))
1267 return hr;
1269 item->object = object;
1270 IUnknown_AddRef(item->object);
1272 if (FAILED(IUnknown_QueryInterface(object, &IID_IMFMediaSource, (void **)&source)))
1273 IUnknown_QueryInterface(object, &IID_IMFByteStream, (void **)&stream);
1275 if (!source && !stream)
1277 WARN("Unsupported object type.\n");
1278 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
1279 return E_UNEXPECTED;
1282 if (source)
1283 item->flags |= MEDIA_ITEM_SOURCE_NEEDS_SHUTDOWN;
1285 if (sync)
1287 if (stream)
1288 hr = IMFSourceResolver_CreateObjectFromByteStream(player->resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE
1289 | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE, player->propstore, &obj_type, &object);
1290 else
1291 IUnknown_AddRef(object);
1293 if (SUCCEEDED(hr))
1294 hr = media_item_set_source(item, object);
1296 IUnknown_Release(object);
1298 if (SUCCEEDED(hr))
1300 *ret = &item->IMFPMediaItem_iface;
1301 IMFPMediaItem_AddRef(*ret);
1304 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
1306 else
1308 if (stream)
1310 hr = IMFSourceResolver_BeginCreateObjectFromByteStream(player->resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE
1311 | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE, player->propstore, NULL,
1312 &player->resolver_callback, (IUnknown *)&item->IMFPMediaItem_iface);
1314 else
1316 /* Resolver callback will check again if item's object is a source. */
1317 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, &player->resolver_callback,
1318 (IUnknown *)&item->IMFPMediaItem_iface);
1321 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
1324 if (source)
1325 IMFMediaSource_Release(source);
1326 if (stream)
1327 IMFByteStream_Release(stream);
1329 return hr;
1332 static HRESULT WINAPI media_player_CreateMediaItemFromObject(IMFPMediaPlayer *iface,
1333 IUnknown *object, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **item)
1335 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1336 HRESULT hr;
1338 TRACE("%p, %p, %d, %Ix, %p.\n", iface, object, sync, user_data, item);
1340 EnterCriticalSection(&player->cs);
1341 if (player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
1342 hr = MF_E_SHUTDOWN;
1343 else
1344 hr = media_player_create_item_from_object(player, object, sync, user_data, item);
1345 LeaveCriticalSection(&player->cs);
1347 return hr;
1350 static HRESULT media_item_create_source_node(struct media_item *item, IMFStreamDescriptor *sd,
1351 IMFTopologyNode **node)
1353 HRESULT hr;
1355 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, node)))
1357 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_SOURCE, (IUnknown *)item->source);
1358 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)item->pd);
1359 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd);
1360 if (item->start_position)
1361 IMFTopologyNode_SetUINT64(*node, &MF_TOPONODE_MEDIASTART, item->start_position);
1362 if (item->stop_position)
1363 IMFTopologyNode_SetUINT64(*node, &MF_TOPONODE_MEDIASTOP, item->stop_position);
1366 return hr;
1369 static HRESULT media_item_create_sink_node(IUnknown *sink, IMFTopologyNode **node)
1371 HRESULT hr;
1373 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, node)))
1374 IMFTopologyNode_SetObject(*node, sink);
1376 return hr;
1379 static HRESULT media_item_create_topology(struct media_player *player, struct media_item *item, IMFTopology **out)
1381 IMFTopologyNode *src_node, *sink_node;
1382 BOOL selected, video_added = FALSE;
1383 IMFStreamDescriptor *sd;
1384 IMFTopology *topology;
1385 unsigned int idx;
1386 IUnknown *sink;
1387 HRESULT hr;
1388 GUID major;
1390 if (FAILED(hr = MFCreateTopology(&topology)))
1391 return hr;
1393 /* Set up branches for all selected streams. */
1395 idx = 0;
1396 while (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, idx++, &selected, &sd)))
1398 if (!selected || FAILED(media_item_get_stream_type(sd, &major)))
1400 IMFStreamDescriptor_Release(sd);
1401 continue;
1404 sink = NULL;
1406 if (SUCCEEDED(IMFStreamDescriptor_GetUnknown(sd, &_MF_CUSTOM_SINK, &IID_IUnknown, (void **)&sink)))
1408 /* User sink is attached as-is. */
1410 else if (IsEqualGUID(&major, &MFMediaType_Audio))
1412 if (FAILED(hr = MFCreateAudioRendererActivate((IMFActivate **)&sink)))
1413 WARN("Failed to create SAR activation object, hr %#lx.\n", hr);
1415 else if (IsEqualGUID(&major, &MFMediaType_Video) && player->output_window && !video_added)
1417 if (FAILED(hr = MFCreateVideoRendererActivate(player->output_window, (IMFActivate **)&sink)))
1418 WARN("Failed to create EVR activation object, hr %#lx.\n", hr);
1419 video_added = SUCCEEDED(hr);
1422 if (sink)
1424 hr = media_item_create_source_node(item, sd, &src_node);
1425 if (SUCCEEDED(hr))
1426 hr = media_item_create_sink_node(sink, &sink_node);
1428 if (SUCCEEDED(hr))
1430 IMFTopology_AddNode(topology, src_node);
1431 IMFTopology_AddNode(topology, sink_node);
1432 IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0);
1435 if (src_node)
1436 IMFTopologyNode_Release(src_node);
1437 if (sink_node)
1438 IMFTopologyNode_Release(sink_node);
1440 IUnknown_Release(sink);
1443 IMFStreamDescriptor_Release(sd);
1446 IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, TRUE);
1448 *out = topology;
1450 return S_OK;
1453 static HRESULT WINAPI media_player_SetMediaItem(IMFPMediaPlayer *iface, IMFPMediaItem *item_iface)
1455 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1456 struct media_item *item;
1457 IMFTopology *topology;
1458 HRESULT hr;
1460 TRACE("%p, %p.\n", iface, item_iface);
1462 if (!item_iface)
1463 return E_POINTER;
1465 item = unsafe_impl_from_IMFPMediaItem(item_iface);
1466 if (item->player != player)
1467 return E_INVALIDARG;
1469 if (FAILED(hr = media_item_create_topology(player, item, &topology)))
1470 return hr;
1472 IMFTopology_SetUnknown(topology, &_MF_TOPO_MEDIA_ITEM, (IUnknown *)item_iface);
1473 hr = IMFMediaSession_SetTopology(player->session, MFSESSION_SETTOPOLOGY_IMMEDIATE, topology);
1474 IMFTopology_Release(topology);
1476 return hr;
1479 static HRESULT WINAPI media_player_ClearMediaItem(IMFPMediaPlayer *iface)
1481 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1483 TRACE("%p.\n", iface);
1485 return IMFMediaSession_SetTopology(player->session, MFSESSION_SETTOPOLOGY_CLEAR_CURRENT, NULL);
1488 static HRESULT WINAPI media_player_GetMediaItem(IMFPMediaPlayer *iface, IMFPMediaItem **item)
1490 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1491 HRESULT hr = S_OK;
1493 TRACE("%p, %p.\n", iface, item);
1495 if (!item)
1496 return E_POINTER;
1498 EnterCriticalSection(&player->cs);
1499 if (player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
1500 hr = MF_E_SHUTDOWN;
1501 else if (!player->item)
1502 hr = MF_E_NOT_FOUND;
1503 else
1505 *item = player->item;
1506 IMFPMediaItem_AddRef(player->item);
1508 LeaveCriticalSection(&player->cs);
1510 return hr;
1513 static HRESULT WINAPI media_player_GetVolume(IMFPMediaPlayer *iface, float *volume)
1515 FIXME("%p, %p.\n", iface, volume);
1517 return E_NOTIMPL;
1520 static HRESULT WINAPI media_player_SetVolume(IMFPMediaPlayer *iface, float volume)
1522 FIXME("%p, %.8e.\n", iface, volume);
1524 return E_NOTIMPL;
1527 static HRESULT WINAPI media_player_GetBalance(IMFPMediaPlayer *iface, float *balance)
1529 FIXME("%p, %p.\n", iface, balance);
1531 return E_NOTIMPL;
1534 static HRESULT WINAPI media_player_SetBalance(IMFPMediaPlayer *iface, float balance)
1536 FIXME("%p, %.8e.\n", iface, balance);
1538 return E_NOTIMPL;
1541 static HRESULT WINAPI media_player_GetMute(IMFPMediaPlayer *iface, BOOL *mute)
1543 FIXME("%p, %p.\n", iface, mute);
1545 return E_NOTIMPL;
1548 static HRESULT WINAPI media_player_SetMute(IMFPMediaPlayer *iface, BOOL mute)
1550 FIXME("%p, %d.\n", iface, mute);
1552 return E_NOTIMPL;
1555 static HRESULT media_player_get_display_control(const struct media_player *player,
1556 IMFVideoDisplayControl **display_control)
1558 HRESULT hr = MFGetService((IUnknown *)player->session, &MR_VIDEO_RENDER_SERVICE,
1559 &IID_IMFVideoDisplayControl, (void **)display_control);
1560 if (SUCCEEDED(hr)) return hr;
1561 return hr == MF_E_SHUTDOWN ? hr : MF_E_INVALIDREQUEST;
1564 static HRESULT WINAPI media_player_GetNativeVideoSize(IMFPMediaPlayer *iface,
1565 SIZE *video, SIZE *arvideo)
1567 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1568 IMFVideoDisplayControl *display_control;
1569 HRESULT hr;
1571 TRACE("%p, %p, %p.\n", iface, video, arvideo);
1573 if (SUCCEEDED(hr = media_player_get_display_control(player, &display_control)))
1575 hr = IMFVideoDisplayControl_GetNativeVideoSize(display_control, video, arvideo);
1576 IMFVideoDisplayControl_Release(display_control);
1579 return hr;
1582 static HRESULT WINAPI media_player_GetIdealVideoSize(IMFPMediaPlayer *iface,
1583 SIZE *min_size, SIZE *max_size)
1585 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1586 IMFVideoDisplayControl *display_control;
1587 HRESULT hr;
1589 TRACE("%p, %p, %p.\n", iface, min_size, max_size);
1591 if (SUCCEEDED(hr = media_player_get_display_control(player, &display_control)))
1593 hr = IMFVideoDisplayControl_GetIdealVideoSize(display_control, min_size, max_size);
1594 IMFVideoDisplayControl_Release(display_control);
1597 return hr;
1600 static HRESULT WINAPI media_player_SetVideoSourceRect(IMFPMediaPlayer *iface,
1601 MFVideoNormalizedRect const *rect)
1603 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1604 IMFVideoDisplayControl *display_control;
1605 RECT dst_rect;
1606 HRESULT hr;
1608 TRACE("%p, %s.\n", iface, debugstr_normalized_rect(rect));
1610 if (!GetClientRect(player->output_window, &dst_rect))
1611 hr = HRESULT_FROM_WIN32(GetLastError());
1612 else if (SUCCEEDED(hr = media_player_get_display_control(player, &display_control)))
1614 hr = IMFVideoDisplayControl_SetVideoPosition(display_control, rect, &dst_rect);
1615 IMFVideoDisplayControl_Release(display_control);
1618 return hr;
1621 static HRESULT WINAPI media_player_GetVideoSourceRect(IMFPMediaPlayer *iface,
1622 MFVideoNormalizedRect *rect)
1624 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1625 IMFVideoDisplayControl *display_control;
1626 HRESULT hr;
1627 RECT dest;
1629 TRACE("%p, %p.\n", iface, rect);
1631 if (SUCCEEDED(hr = media_player_get_display_control(player, &display_control)))
1633 hr = IMFVideoDisplayControl_GetVideoPosition(display_control, rect, &dest);
1634 IMFVideoDisplayControl_Release(display_control);
1637 return hr;
1640 static HRESULT WINAPI media_player_SetAspectRatioMode(IMFPMediaPlayer *iface, DWORD mode)
1642 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1643 IMFVideoDisplayControl *display_control;
1644 HRESULT hr;
1646 TRACE("%p, %lu.\n", iface, mode);
1648 if (SUCCEEDED(hr = media_player_get_display_control(player, &display_control)))
1650 hr = IMFVideoDisplayControl_SetAspectRatioMode(display_control, mode);
1651 IMFVideoDisplayControl_Release(display_control);
1654 return hr;
1657 static HRESULT WINAPI media_player_GetAspectRatioMode(IMFPMediaPlayer *iface,
1658 DWORD *mode)
1660 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1661 IMFVideoDisplayControl *display_control;
1662 HRESULT hr;
1664 TRACE("%p, %p.\n", iface, mode);
1666 if (SUCCEEDED(hr = media_player_get_display_control(player, &display_control)))
1668 hr = IMFVideoDisplayControl_GetAspectRatioMode(display_control, mode);
1669 IMFVideoDisplayControl_Release(display_control);
1672 return hr;
1675 static HRESULT WINAPI media_player_GetVideoWindow(IMFPMediaPlayer *iface, HWND *window)
1677 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1679 TRACE("%p, %p.\n", iface, window);
1681 *window = player->output_window;
1683 return S_OK;
1686 static HRESULT WINAPI media_player_UpdateVideo(IMFPMediaPlayer *iface)
1688 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1689 IMFVideoDisplayControl *display_control;
1690 HRESULT hr;
1691 RECT rect;
1693 TRACE("%p.\n", iface);
1695 if (SUCCEEDED(hr = media_player_get_display_control(player, &display_control)))
1697 if (GetClientRect(player->output_window, &rect))
1698 hr = IMFVideoDisplayControl_SetVideoPosition(display_control, NULL, &rect);
1699 if (SUCCEEDED(hr))
1700 hr = IMFVideoDisplayControl_RepaintVideo(display_control);
1701 IMFVideoDisplayControl_Release(display_control);
1704 return hr;
1707 static HRESULT WINAPI media_player_SetBorderColor(IMFPMediaPlayer *iface, COLORREF color)
1709 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1710 IMFVideoDisplayControl *display_control;
1711 HRESULT hr;
1713 TRACE("%p, %#lx.\n", iface, color);
1715 if (SUCCEEDED(hr = media_player_get_display_control(player, &display_control)))
1717 hr = IMFVideoDisplayControl_SetBorderColor(display_control, color);
1718 IMFVideoDisplayControl_Release(display_control);
1721 return hr;
1724 static HRESULT WINAPI media_player_GetBorderColor(IMFPMediaPlayer *iface, COLORREF *color)
1726 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1727 IMFVideoDisplayControl *display_control;
1728 HRESULT hr;
1730 TRACE("%p, %p.\n", iface, color);
1732 if (SUCCEEDED(hr = media_player_get_display_control(player, &display_control)))
1734 hr = IMFVideoDisplayControl_GetBorderColor(display_control, color);
1735 IMFVideoDisplayControl_Release(display_control);
1738 return hr;
1741 static HRESULT WINAPI media_player_InsertEffect(IMFPMediaPlayer *iface, IUnknown *effect,
1742 BOOL optional)
1744 FIXME("%p, %p, %d.\n", iface, effect, optional);
1746 return E_NOTIMPL;
1749 static HRESULT WINAPI media_player_RemoveEffect(IMFPMediaPlayer *iface, IUnknown *effect)
1751 FIXME("%p, %p.\n", iface, effect);
1753 return E_NOTIMPL;
1756 static HRESULT WINAPI media_player_RemoveAllEffects(IMFPMediaPlayer *iface)
1758 FIXME("%p.\n", iface);
1760 return E_NOTIMPL;
1763 static HRESULT WINAPI media_player_Shutdown(IMFPMediaPlayer *iface)
1765 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1767 TRACE("%p.\n", iface);
1769 EnterCriticalSection(&player->cs);
1770 media_player_set_state(player, MFP_MEDIAPLAYER_STATE_SHUTDOWN);
1771 if (player->item)
1773 IMFPMediaItem_Release(player->item);
1774 player->item = NULL;
1776 LeaveCriticalSection(&player->cs);
1778 return S_OK;
1781 static const IMFPMediaPlayerVtbl media_player_vtbl =
1783 media_player_QueryInterface,
1784 media_player_AddRef,
1785 media_player_Release,
1786 media_player_Play,
1787 media_player_Pause,
1788 media_player_Stop,
1789 media_player_FrameStep,
1790 media_player_SetPosition,
1791 media_player_GetPosition,
1792 media_player_GetDuration,
1793 media_player_SetRate,
1794 media_player_GetRate,
1795 media_player_GetSupportedRates,
1796 media_player_GetState,
1797 media_player_CreateMediaItemFromURL,
1798 media_player_CreateMediaItemFromObject,
1799 media_player_SetMediaItem,
1800 media_player_ClearMediaItem,
1801 media_player_GetMediaItem,
1802 media_player_GetVolume,
1803 media_player_SetVolume,
1804 media_player_GetBalance,
1805 media_player_SetBalance,
1806 media_player_GetMute,
1807 media_player_SetMute,
1808 media_player_GetNativeVideoSize,
1809 media_player_GetIdealVideoSize,
1810 media_player_SetVideoSourceRect,
1811 media_player_GetVideoSourceRect,
1812 media_player_SetAspectRatioMode,
1813 media_player_GetAspectRatioMode,
1814 media_player_GetVideoWindow,
1815 media_player_UpdateVideo,
1816 media_player_SetBorderColor,
1817 media_player_GetBorderColor,
1818 media_player_InsertEffect,
1819 media_player_RemoveEffect,
1820 media_player_RemoveAllEffects,
1821 media_player_Shutdown,
1824 static HRESULT WINAPI media_player_propstore_QueryInterface(IPropertyStore *iface,
1825 REFIID riid, void **obj)
1827 struct media_player *player = impl_from_IPropertyStore(iface);
1828 return IMFPMediaPlayer_QueryInterface(&player->IMFPMediaPlayer_iface, riid, obj);
1831 static ULONG WINAPI media_player_propstore_AddRef(IPropertyStore *iface)
1833 struct media_player *player = impl_from_IPropertyStore(iface);
1834 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1837 static ULONG WINAPI media_player_propstore_Release(IPropertyStore *iface)
1839 struct media_player *player = impl_from_IPropertyStore(iface);
1840 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1843 static HRESULT WINAPI media_player_propstore_GetCount(IPropertyStore *iface, DWORD *count)
1845 struct media_player *player = impl_from_IPropertyStore(iface);
1847 TRACE("%p, %p.\n", iface, count);
1849 return IPropertyStore_GetCount(player->propstore, count);
1852 static HRESULT WINAPI media_player_propstore_GetAt(IPropertyStore *iface, DWORD prop, PROPERTYKEY *key)
1854 struct media_player *player = impl_from_IPropertyStore(iface);
1856 TRACE("%p, %lu, %p.\n", iface, prop, key);
1858 return IPropertyStore_GetAt(player->propstore, prop, key);
1861 static HRESULT WINAPI media_player_propstore_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *value)
1863 struct media_player *player = impl_from_IPropertyStore(iface);
1865 TRACE("%p, %p, %p.\n", iface, key, value);
1867 return IPropertyStore_GetValue(player->propstore, key, value);
1870 static HRESULT WINAPI media_player_propstore_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT value)
1872 struct media_player *player = impl_from_IPropertyStore(iface);
1874 TRACE("%p, %p, %p.\n", iface, key, value);
1876 return IPropertyStore_SetValue(player->propstore, key, value);
1879 static HRESULT WINAPI media_player_propstore_Commit(IPropertyStore *iface)
1881 struct media_player *player = impl_from_IPropertyStore(iface);
1883 TRACE("%p.\n", iface);
1885 return IPropertyStore_Commit(player->propstore);
1888 static const IPropertyStoreVtbl media_player_propstore_vtbl =
1890 media_player_propstore_QueryInterface,
1891 media_player_propstore_AddRef,
1892 media_player_propstore_Release,
1893 media_player_propstore_GetCount,
1894 media_player_propstore_GetAt,
1895 media_player_propstore_GetValue,
1896 media_player_propstore_SetValue,
1897 media_player_propstore_Commit,
1900 static HRESULT WINAPI media_player_callback_QueryInterface(IMFAsyncCallback *iface,
1901 REFIID riid, void **obj)
1903 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
1904 IsEqualIID(riid, &IID_IUnknown))
1906 *obj = iface;
1907 IMFAsyncCallback_AddRef(iface);
1908 return S_OK;
1911 *obj = NULL;
1912 return E_NOINTERFACE;
1915 static ULONG WINAPI media_player_resolver_callback_AddRef(IMFAsyncCallback *iface)
1917 struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
1918 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1921 static ULONG WINAPI media_player_resolver_callback_Release(IMFAsyncCallback *iface)
1923 struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
1924 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1927 static HRESULT WINAPI media_player_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags,
1928 DWORD *queue)
1930 return E_NOTIMPL;
1933 static HRESULT WINAPI media_player_resolver_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1935 struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
1936 struct media_event *event;
1937 IUnknown *object, *state;
1938 MF_OBJECT_TYPE obj_type;
1939 struct media_item *item;
1940 HRESULT hr;
1942 if (FAILED(IMFAsyncResult_GetState(result, &state)))
1943 return S_OK;
1945 item = impl_from_IMFPMediaItem((IMFPMediaItem *)state);
1947 if (item->object)
1949 if (FAILED(hr = IUnknown_QueryInterface(item->object, &IID_IMFMediaSource, (void **)&object)))
1950 hr = IMFSourceResolver_EndCreateObjectFromByteStream(player->resolver, result, &obj_type, &object);
1952 else
1953 hr = IMFSourceResolver_EndCreateObjectFromURL(player->resolver, result, &obj_type, &object);
1955 if (SUCCEEDED(hr))
1957 hr = media_item_set_source(item, object);
1958 IUnknown_Release(object);
1961 if (FAILED(hr))
1962 WARN("Failed to set media source, hr %#lx.\n", hr);
1964 if (FAILED(media_event_create(player, MFP_EVENT_TYPE_MEDIAITEM_CREATED, hr,
1965 &item->IMFPMediaItem_iface, &event)))
1967 WARN("Failed to create event object.\n");
1968 IUnknown_Release(state);
1969 return S_OK;
1971 event->u.item_created.dwUserData = item->user_data;
1973 media_player_queue_event(player, event);
1975 IUnknown_Release(&event->IUnknown_iface);
1976 IUnknown_Release(state);
1978 return S_OK;
1981 static const IMFAsyncCallbackVtbl media_player_resolver_callback_vtbl =
1983 media_player_callback_QueryInterface,
1984 media_player_resolver_callback_AddRef,
1985 media_player_resolver_callback_Release,
1986 media_player_callback_GetParameters,
1987 media_player_resolver_callback_Invoke,
1990 static ULONG WINAPI media_player_events_callback_AddRef(IMFAsyncCallback *iface)
1992 struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
1993 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1996 static ULONG WINAPI media_player_events_callback_Release(IMFAsyncCallback *iface)
1998 struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
1999 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
2002 static HRESULT WINAPI media_player_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
2004 struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
2005 struct media_event *event;
2006 IUnknown *state;
2008 if (FAILED(IMFAsyncResult_GetState(result, &state)))
2009 return S_OK;
2011 event = impl_event_from_IUnknown(state);
2013 if (player->callback)
2014 IMFPMediaPlayerCallback_OnMediaPlayerEvent(player->callback, &event->u.header);
2016 IUnknown_Release(state);
2018 return S_OK;
2021 static const IMFAsyncCallbackVtbl media_player_events_callback_vtbl =
2023 media_player_callback_QueryInterface,
2024 media_player_events_callback_AddRef,
2025 media_player_events_callback_Release,
2026 media_player_callback_GetParameters,
2027 media_player_events_callback_Invoke,
2030 static ULONG WINAPI media_player_session_events_callback_AddRef(IMFAsyncCallback *iface)
2032 struct media_player *player = impl_from_session_events_IMFAsyncCallback(iface);
2033 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
2036 static ULONG WINAPI media_player_session_events_callback_Release(IMFAsyncCallback *iface)
2038 struct media_player *player = impl_from_session_events_IMFAsyncCallback(iface);
2039 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
2042 static void media_player_change_state(struct media_player *player, MFP_MEDIAPLAYER_STATE state,
2043 HRESULT event_status, struct media_event **event)
2045 MFP_EVENT_TYPE event_type;
2047 EnterCriticalSection(&player->cs);
2049 if (state == MFP_MEDIAPLAYER_STATE_PLAYING)
2050 event_type = MFP_EVENT_TYPE_PLAY;
2051 else if (state == MFP_MEDIAPLAYER_STATE_PAUSED)
2052 event_type = MFP_EVENT_TYPE_PAUSE;
2053 else
2054 event_type = MFP_EVENT_TYPE_STOP;
2056 media_player_set_state(player, state);
2057 media_event_create(player, event_type, event_status, player->item, event);
2059 LeaveCriticalSection(&player->cs);
2062 static void media_player_set_item(struct media_player *player, IMFTopology *topology, HRESULT event_status,
2063 struct media_event **event)
2065 IMFPMediaItem *item;
2067 if (FAILED(IMFTopology_GetUnknown(topology, &_MF_TOPO_MEDIA_ITEM, &IID_IMFPMediaItem, (void **)&item)))
2068 return;
2070 EnterCriticalSection(&player->cs);
2072 if (player->item)
2073 IMFPMediaItem_Release(player->item);
2074 player->item = item;
2075 IMFPMediaItem_AddRef(player->item);
2077 media_event_create(player, MFP_EVENT_TYPE_MEDIAITEM_SET, event_status, item, event);
2079 LeaveCriticalSection(&player->cs);
2081 IMFPMediaItem_Release(item);
2084 static void media_player_clear_item(struct media_player *player, HRESULT event_status,
2085 struct media_event **event)
2087 IMFPMediaItem *item;
2089 EnterCriticalSection(&player->cs);
2091 item = player->item;
2092 player->item = NULL;
2094 media_event_create(player, MFP_EVENT_TYPE_MEDIAITEM_SET, event_status, item, event);
2096 LeaveCriticalSection(&player->cs);
2099 static void media_player_create_forward_event(struct media_player *player, HRESULT event_status, IMFMediaEvent *session_event,
2100 struct media_event **event)
2102 EnterCriticalSection(&player->cs);
2104 if (SUCCEEDED(media_event_create(player, MFP_EVENT_TYPE_MF, event_status, player->item, event)))
2106 IMFMediaEvent_GetType(session_event, &(*event)->u.event.MFEventType);
2107 (*event)->u.event.pMFMediaEvent = session_event;
2108 IMFMediaEvent_AddRef((*event)->u.event.pMFMediaEvent);
2111 LeaveCriticalSection(&player->cs);
2114 static void media_player_playback_ended(struct media_player *player, HRESULT event_status,
2115 struct media_event **event)
2117 EnterCriticalSection(&player->cs);
2119 media_player_set_state(player, MFP_MEDIAPLAYER_STATE_STOPPED);
2120 media_event_create(player, MFP_EVENT_TYPE_PLAYBACK_ENDED, event_status, player->item, event);
2122 LeaveCriticalSection(&player->cs);
2125 static void media_player_rate_changed(struct media_player *player, HRESULT event_status,
2126 float rate, struct media_event **event)
2128 EnterCriticalSection(&player->cs);
2130 if (SUCCEEDED(media_event_create(player, MFP_EVENT_TYPE_RATE_SET, event_status, player->item, event)))
2131 (*event)->u.rate_set.flRate = rate;
2133 LeaveCriticalSection(&player->cs);
2136 static HRESULT WINAPI media_player_session_events_callback_Invoke(IMFAsyncCallback *iface,
2137 IMFAsyncResult *result)
2139 struct media_player *player = impl_from_session_events_IMFAsyncCallback(iface);
2140 MediaEventType session_event_type = MEUnknown;
2141 struct media_event *event = NULL;
2142 IMFMediaEvent *session_event;
2143 MFP_MEDIAPLAYER_STATE state;
2144 HRESULT hr, event_status;
2145 IMFTopology *topology;
2146 unsigned int status;
2147 PROPVARIANT value;
2148 float rate;
2150 if (FAILED(hr = IMFMediaSession_EndGetEvent(player->session, result, &session_event)))
2151 return S_OK;
2153 IMFMediaEvent_GetType(session_event, &session_event_type);
2154 IMFMediaEvent_GetStatus(session_event, &event_status);
2156 switch (session_event_type)
2158 case MESessionStarted:
2159 case MESessionStopped:
2160 case MESessionPaused:
2162 if (session_event_type == MESessionStarted)
2163 state = MFP_MEDIAPLAYER_STATE_PLAYING;
2164 else if (session_event_type == MESessionPaused)
2165 state = MFP_MEDIAPLAYER_STATE_PAUSED;
2166 else
2167 state = MFP_MEDIAPLAYER_STATE_STOPPED;
2169 media_player_change_state(player, state, event_status, &event);
2171 break;
2173 case MESessionTopologySet:
2175 value.vt = VT_EMPTY;
2176 if (SUCCEEDED(IMFMediaEvent_GetValue(session_event, &value)))
2178 if (value.vt == VT_EMPTY)
2180 media_player_clear_item(player, event_status, &event);
2182 else if (value.vt == VT_UNKNOWN && value.punkVal &&
2183 SUCCEEDED(IUnknown_QueryInterface(value.punkVal, &IID_IMFTopology, (void **)&topology)))
2185 media_player_set_item(player, topology, event_status, &event);
2186 IMFTopology_Release(topology);
2188 PropVariantClear(&value);
2191 break;
2193 case MESessionTopologyStatus:
2195 if (SUCCEEDED(IMFMediaEvent_GetUINT32(session_event, &MF_EVENT_TOPOLOGY_STATUS, &status)) &&
2196 status == MF_TOPOSTATUS_ENDED)
2198 media_player_playback_ended(player, event_status, &event);
2201 break;
2203 case MESessionRateChanged:
2205 rate = 0.0f;
2206 if (SUCCEEDED(IMFMediaEvent_GetValue(session_event, &value)))
2208 if (value.vt == VT_R4)
2209 rate = value.fltVal;
2210 PropVariantClear(&value);
2213 media_player_rate_changed(player, event_status, rate, &event);
2215 break;
2217 case MEBufferingStarted:
2218 case MEBufferingStopped:
2219 case MEExtendedType:
2220 case MEReconnectStart:
2221 case MEReconnectEnd:
2222 case MERendererEvent:
2223 case MEStreamSinkFormatChanged:
2225 media_player_create_forward_event(player, event_status, session_event, &event);
2227 break;
2229 case MEError:
2231 media_event_create(player, MFP_EVENT_TYPE_ERROR, event_status, NULL, &event);
2233 break;
2235 default:
2239 if (event)
2241 media_player_queue_event(player, event);
2242 IUnknown_Release(&event->IUnknown_iface);
2245 IMFMediaSession_BeginGetEvent(player->session, &player->session_events_callback, NULL);
2246 IMFMediaEvent_Release(session_event);
2248 return S_OK;
2251 static const IMFAsyncCallbackVtbl media_player_session_events_callback_vtbl =
2253 media_player_callback_QueryInterface,
2254 media_player_session_events_callback_AddRef,
2255 media_player_session_events_callback_Release,
2256 media_player_callback_GetParameters,
2257 media_player_session_events_callback_Invoke,
2260 /***********************************************************************
2261 * MFPCreateMediaPlayer (mfplay.@)
2263 HRESULT WINAPI MFPCreateMediaPlayer(const WCHAR *url, BOOL start_playback, MFP_CREATION_OPTIONS options,
2264 IMFPMediaPlayerCallback *callback, HWND window, IMFPMediaPlayer **player)
2266 struct media_player *object;
2267 IMFPMediaItem *item;
2268 HRESULT hr;
2270 TRACE("%s, %d, %#x, %p, %p, %p.\n", debugstr_w(url), start_playback, options, callback, window, player);
2272 if (!player)
2273 return E_POINTER;
2275 *player = NULL;
2277 if (!url && start_playback)
2278 return E_INVALIDARG;
2280 if (!(object = calloc(1, sizeof(*object))))
2281 return E_OUTOFMEMORY;
2283 platform_startup();
2285 object->IMFPMediaPlayer_iface.lpVtbl = &media_player_vtbl;
2286 object->IPropertyStore_iface.lpVtbl = &media_player_propstore_vtbl;
2287 object->resolver_callback.lpVtbl = &media_player_resolver_callback_vtbl;
2288 object->events_callback.lpVtbl = &media_player_events_callback_vtbl;
2289 object->session_events_callback.lpVtbl = &media_player_session_events_callback_vtbl;
2290 object->refcount = 1;
2291 object->callback = callback;
2292 if (object->callback)
2293 IMFPMediaPlayerCallback_AddRef(object->callback);
2294 object->options = options;
2295 object->output_window = window;
2296 InitializeCriticalSection(&object->cs);
2297 if (FAILED(hr = CreatePropertyStore(&object->propstore)))
2298 goto failed;
2299 if (FAILED(hr = MFCreateSourceResolver(&object->resolver)))
2300 goto failed;
2301 if (FAILED(hr = MFCreateMediaSession(NULL, &object->session)))
2302 goto failed;
2303 if (FAILED(hr = IMFMediaSession_BeginGetEvent(object->session, &object->session_events_callback, NULL)))
2304 goto failed;
2305 if (!(object->options & MFP_OPTION_FREE_THREADED_CALLBACK))
2307 object->event_window = CreateWindowW(eventclassW, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE,
2308 0, mfplay_instance, NULL);
2311 if (url)
2313 if (FAILED(hr = media_player_create_item_from_url(object, url, TRUE, 0, &item)))
2315 WARN("Failed to create media item, hr %#lx.\n", hr);
2316 goto failed;
2319 hr = IMFPMediaPlayer_SetMediaItem(&object->IMFPMediaPlayer_iface, item);
2320 IMFPMediaItem_Release(item);
2321 if (FAILED(hr))
2323 WARN("Failed to set media item, hr %#lx.\n", hr);
2324 goto failed;
2327 if (start_playback)
2328 IMFPMediaPlayer_Play(&object->IMFPMediaPlayer_iface);
2331 *player = &object->IMFPMediaPlayer_iface;
2333 return S_OK;
2335 failed:
2337 IMFPMediaPlayer_Release(&object->IMFPMediaPlayer_iface);
2339 return hr;
2342 static void media_player_register_window_class(void)
2344 WNDCLASSW cls = { 0 };
2346 cls.lpfnWndProc = media_player_event_proc;
2347 cls.hInstance = mfplay_instance;
2348 cls.lpszClassName = eventclassW;
2350 RegisterClassW(&cls);
2353 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
2355 switch (reason)
2357 case DLL_PROCESS_ATTACH:
2358 mfplay_instance = instance;
2359 DisableThreadLibraryCalls(instance);
2360 media_player_register_window_class();
2361 break;
2362 case DLL_PROCESS_DETACH:
2363 if (reserved) break;
2364 UnregisterClassW(eventclassW, instance);
2365 break;
2368 return TRUE;