mfplay: Keep start/stop positions for items.
[wine.git] / dlls / mfplay / player.c
blob0e41656f0c803861c3607cf2aa2ee99185673acb
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;
66 LONGLONG start_position;
67 LONGLONG stop_position;
70 struct media_player
72 IMFPMediaPlayer IMFPMediaPlayer_iface;
73 IPropertyStore IPropertyStore_iface;
74 IMFAsyncCallback resolver_callback;
75 IMFAsyncCallback events_callback;
76 IMFAsyncCallback session_events_callback;
77 LONG refcount;
78 IMFPMediaPlayerCallback *callback;
79 IPropertyStore *propstore;
80 IMFSourceResolver *resolver;
81 IMFMediaSession *session;
82 IMFPMediaItem *item;
83 MFP_CREATION_OPTIONS options;
84 MFP_MEDIAPLAYER_STATE state;
85 HWND event_window;
86 HWND output_window;
87 CRITICAL_SECTION cs;
90 struct generic_event
92 MFP_EVENT_HEADER header;
93 IMFPMediaItem *item;
96 struct media_event
98 IUnknown IUnknown_iface;
99 LONG refcount;
100 union
102 MFP_EVENT_HEADER header;
103 struct generic_event generic;
104 MFP_PLAY_EVENT play;
105 MFP_PAUSE_EVENT pause;
106 MFP_STOP_EVENT stop;
107 MFP_POSITION_SET_EVENT position_set;
108 MFP_RATE_SET_EVENT rate_set;
109 MFP_MEDIAITEM_CREATED_EVENT item_created;
110 MFP_MEDIAITEM_SET_EVENT item_set;
111 MFP_MEDIAITEM_CLEARED_EVENT item_cleared;
112 MFP_MF_EVENT event;
113 MFP_ERROR_EVENT error;
114 MFP_PLAYBACK_ENDED_EVENT ended;
115 MFP_ACQUIRE_USER_CREDENTIAL_EVENT acquire_creds;
116 } u;
119 static struct media_player *impl_from_IMFPMediaPlayer(IMFPMediaPlayer *iface)
121 return CONTAINING_RECORD(iface, struct media_player, IMFPMediaPlayer_iface);
124 static struct media_player *impl_from_IPropertyStore(IPropertyStore *iface)
126 return CONTAINING_RECORD(iface, struct media_player, IPropertyStore_iface);
129 static struct media_player *impl_from_resolver_IMFAsyncCallback(IMFAsyncCallback *iface)
131 return CONTAINING_RECORD(iface, struct media_player, resolver_callback);
134 static struct media_player *impl_from_events_IMFAsyncCallback(IMFAsyncCallback *iface)
136 return CONTAINING_RECORD(iface, struct media_player, events_callback);
139 static struct media_player *impl_from_session_events_IMFAsyncCallback(IMFAsyncCallback *iface)
141 return CONTAINING_RECORD(iface, struct media_player, session_events_callback);
144 static struct media_item *impl_from_IMFPMediaItem(IMFPMediaItem *iface)
146 return CONTAINING_RECORD(iface, struct media_item, IMFPMediaItem_iface);
149 static struct media_event *impl_event_from_IUnknown(IUnknown *iface)
151 return CONTAINING_RECORD(iface, struct media_event, IUnknown_iface);
154 static HRESULT WINAPI media_event_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
156 if (IsEqualIID(riid, &IID_IUnknown))
158 *obj = iface;
159 IUnknown_AddRef(iface);
160 return S_OK;
163 *obj = NULL;
164 return E_NOINTERFACE;
167 static ULONG WINAPI media_event_AddRef(IUnknown *iface)
169 struct media_event *event = impl_event_from_IUnknown(iface);
170 ULONG refcount = InterlockedIncrement(&event->refcount);
172 TRACE("%p, refcount %u.\n", iface, refcount);
174 return refcount;
177 static ULONG WINAPI media_event_Release(IUnknown *iface)
179 struct media_event *event = impl_event_from_IUnknown(iface);
180 ULONG refcount = InterlockedDecrement(&event->refcount);
182 TRACE("%p, refcount %u.\n", iface, refcount);
184 if (!refcount)
186 if (event->u.header.pMediaPlayer)
187 IMFPMediaPlayer_Release(event->u.header.pMediaPlayer);
188 if (event->u.header.pPropertyStore)
189 IPropertyStore_Release(event->u.header.pPropertyStore);
191 switch (event->u.header.eEventType)
193 /* Most types share same layout. */
194 case MFP_EVENT_TYPE_PLAY:
195 case MFP_EVENT_TYPE_PAUSE:
196 case MFP_EVENT_TYPE_STOP:
197 case MFP_EVENT_TYPE_POSITION_SET:
198 case MFP_EVENT_TYPE_RATE_SET:
199 case MFP_EVENT_TYPE_MEDIAITEM_CREATED:
200 case MFP_EVENT_TYPE_MEDIAITEM_SET:
201 case MFP_EVENT_TYPE_FRAME_STEP:
202 case MFP_EVENT_TYPE_MEDIAITEM_CLEARED:
203 case MFP_EVENT_TYPE_PLAYBACK_ENDED:
204 if (event->u.generic.item)
205 IMFPMediaItem_Release(event->u.generic.item);
206 break;
207 case MFP_EVENT_TYPE_MF:
208 if (event->u.event.pMFMediaEvent)
209 IMFMediaEvent_Release(event->u.event.pMFMediaEvent);
210 if (event->u.event.pMediaItem)
211 IMFPMediaItem_Release(event->u.event.pMediaItem);
212 break;
213 default:
214 FIXME("Unsupported event %u.\n", event->u.header.eEventType);
215 break;
218 free(event);
221 return refcount;
224 static const IUnknownVtbl media_event_vtbl =
226 media_event_QueryInterface,
227 media_event_AddRef,
228 media_event_Release,
231 static HRESULT media_event_create(struct media_player *player, MFP_EVENT_TYPE event_type,
232 HRESULT hr, IMFPMediaItem *item, struct media_event **event)
234 struct media_event *object;
236 if (!(object = calloc(1, sizeof(*object))))
237 return E_OUTOFMEMORY;
239 object->IUnknown_iface.lpVtbl = &media_event_vtbl;
240 object->refcount = 1;
241 object->u.header.eEventType = event_type;
242 object->u.header.hrEvent = hr;
243 object->u.header.pMediaPlayer = &player->IMFPMediaPlayer_iface;
244 IMFPMediaPlayer_AddRef(object->u.header.pMediaPlayer);
245 object->u.header.eState = player->state;
246 switch (event_type)
248 case MFP_EVENT_TYPE_PLAY:
249 case MFP_EVENT_TYPE_PAUSE:
250 case MFP_EVENT_TYPE_STOP:
251 case MFP_EVENT_TYPE_POSITION_SET:
252 case MFP_EVENT_TYPE_RATE_SET:
253 case MFP_EVENT_TYPE_MEDIAITEM_CREATED:
254 case MFP_EVENT_TYPE_MEDIAITEM_SET:
255 case MFP_EVENT_TYPE_FRAME_STEP:
256 case MFP_EVENT_TYPE_MEDIAITEM_CLEARED:
257 case MFP_EVENT_TYPE_PLAYBACK_ENDED:
258 object->u.generic.item = item;
259 if (object->u.generic.item)
260 IMFPMediaItem_AddRef(object->u.generic.item);
261 break;
262 case MFP_EVENT_TYPE_MF:
263 object->u.event.pMediaItem = item;
264 if (object->u.event.pMediaItem)
265 IMFPMediaItem_AddRef(object->u.event.pMediaItem);
266 break;
267 default:
271 /* FIXME: set properties for some events? */
273 *event = object;
275 return S_OK;
278 static LRESULT WINAPI media_player_event_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
280 struct media_event *event = (void *)lparam;
281 struct media_player *player;
283 if (msg == WM_USER)
285 player = impl_from_IMFPMediaPlayer(event->u.header.pMediaPlayer);
286 if (player->callback)
287 IMFPMediaPlayerCallback_OnMediaPlayerEvent(player->callback, &event->u.header);
288 IUnknown_Release(&event->IUnknown_iface);
289 return 0;
292 return DefWindowProcW(hwnd, msg, wparam, lparam);
295 static void media_player_set_state(struct media_player *player, MFP_MEDIAPLAYER_STATE state)
297 if (player->state != MFP_MEDIAPLAYER_STATE_SHUTDOWN)
299 if (state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
300 IMFMediaSession_Shutdown(player->session);
301 player->state = state;
305 static HRESULT WINAPI media_item_QueryInterface(IMFPMediaItem *iface, REFIID riid, void **obj)
307 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
309 if (IsEqualIID(riid, &IID_IMFPMediaItem) ||
310 IsEqualIID(riid, &IID_IUnknown))
312 *obj = iface;
313 IMFPMediaItem_AddRef(iface);
314 return S_OK;
317 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
318 *obj = NULL;
319 return E_NOINTERFACE;
322 static ULONG WINAPI media_item_AddRef(IMFPMediaItem *iface)
324 struct media_item *item = impl_from_IMFPMediaItem(iface);
325 ULONG refcount = InterlockedIncrement(&item->refcount);
327 TRACE("%p, refcount %u.\n", iface, refcount);
329 return refcount;
332 static ULONG WINAPI media_item_Release(IMFPMediaItem *iface)
334 struct media_item *item = impl_from_IMFPMediaItem(iface);
335 ULONG refcount = InterlockedDecrement(&item->refcount);
337 TRACE("%p, refcount %u.\n", iface, refcount);
339 if (!refcount)
341 if (item->player)
342 IMFPMediaPlayer_Release(item->player);
343 if (item->source)
344 IMFMediaSource_Release(item->source);
345 if (item->pd)
346 IMFPresentationDescriptor_Release(item->pd);
347 if (item->object)
348 IUnknown_Release(item->object);
349 free(item->url);
350 free(item);
353 return refcount;
356 static HRESULT WINAPI media_item_GetMediaPlayer(IMFPMediaItem *iface,
357 IMFPMediaPlayer **player)
359 struct media_item *item = impl_from_IMFPMediaItem(iface);
361 TRACE("%p, %p.\n", iface, player);
363 *player = item->player;
364 IMFPMediaPlayer_AddRef(*player);
366 return S_OK;
369 static HRESULT WINAPI media_item_GetURL(IMFPMediaItem *iface, LPWSTR *url)
371 struct media_item *item = impl_from_IMFPMediaItem(iface);
373 TRACE("%p, %p.\n", iface, url);
375 if (!item->url)
376 return MF_E_NOT_FOUND;
378 if (!(*url = CoTaskMemAlloc((wcslen(item->url) + 1) * sizeof(*item->url))))
379 return E_OUTOFMEMORY;
381 wcscpy(*url, item->url);
383 return S_OK;
386 static HRESULT WINAPI media_item_GetObject(IMFPMediaItem *iface, IUnknown **object)
388 struct media_item *item = impl_from_IMFPMediaItem(iface);
390 TRACE("%p, %p.\n", iface, object);
392 if (!item->object)
393 return MF_E_NOT_FOUND;
395 *object = item->object;
396 IUnknown_AddRef(*object);
398 return S_OK;
401 static HRESULT WINAPI media_item_GetUserData(IMFPMediaItem *iface, DWORD_PTR *user_data)
403 struct media_item *item = impl_from_IMFPMediaItem(iface);
405 TRACE("%p, %p.\n", iface, user_data);
407 *user_data = item->user_data;
409 return S_OK;
412 static HRESULT WINAPI media_item_SetUserData(IMFPMediaItem *iface, DWORD_PTR user_data)
414 struct media_item *item = impl_from_IMFPMediaItem(iface);
416 TRACE("%p, %lx.\n", iface, user_data);
418 item->user_data = user_data;
420 return S_OK;
423 static HRESULT media_item_set_position(const GUID *format, const PROPVARIANT *position, LARGE_INTEGER *ret)
425 ret->QuadPart = 0;
427 if (format && !IsEqualGUID(format, &MFP_POSITIONTYPE_100NS))
428 return E_INVALIDARG;
430 if ((format != NULL) ^ (position != NULL))
431 return E_POINTER;
433 if (position && position->vt != VT_EMPTY && position->vt != VT_I8)
434 return E_INVALIDARG;
436 if ((!format && !position) || position->vt == VT_EMPTY)
437 return S_OK;
439 if (position->hVal.QuadPart == 0)
440 return MF_E_OUT_OF_RANGE;
442 ret->QuadPart = position->hVal.QuadPart;
444 return S_OK;
447 static void media_item_get_position(LONGLONG value, GUID *format, PROPVARIANT *position)
449 if (!format)
450 return;
452 memcpy(format, &MFP_POSITIONTYPE_100NS, sizeof(*format));
454 if (value)
456 position->vt = VT_I8;
457 position->hVal.QuadPart = value;
461 static HRESULT WINAPI media_item_GetStartStopPosition(IMFPMediaItem *iface, GUID *start_format,
462 PROPVARIANT *start_position, GUID *stop_format, PROPVARIANT *stop_position)
464 struct media_item *item = impl_from_IMFPMediaItem(iface);
466 TRACE("%p, %p, %p, %p, %p.\n", iface, start_format, start_position, stop_format, stop_position);
468 if (start_position)
469 start_position->vt = VT_EMPTY;
470 if (stop_position)
471 stop_position->vt = VT_EMPTY;
473 if (((start_format != NULL) ^ (start_position != NULL)) ||
474 ((stop_format != NULL) ^ (stop_position != NULL)))
476 return E_POINTER;
479 media_item_get_position(item->start_position, start_format, start_position);
480 media_item_get_position(item->stop_position, stop_format, stop_position);
482 return S_OK;
485 static HRESULT WINAPI media_item_SetStartStopPosition(IMFPMediaItem *iface, const GUID *start_format,
486 const PROPVARIANT *start_position, const GUID *stop_format, const PROPVARIANT *stop_position)
488 struct media_item *item = impl_from_IMFPMediaItem(iface);
489 LARGE_INTEGER start, stop;
490 HRESULT hr;
492 TRACE("%p, %s, %p, %s, %p.\n", iface, debugstr_guid(start_format), start_position,
493 debugstr_guid(stop_format), stop_position);
495 hr = media_item_set_position(start_format, start_position, &start);
496 if (SUCCEEDED(hr))
497 hr = media_item_set_position(stop_format, stop_position, &stop);
499 if (FAILED(hr))
500 return hr;
502 if (start.QuadPart > stop.QuadPart)
503 return MF_E_OUT_OF_RANGE;
505 item->start_position = start.QuadPart;
506 item->stop_position = stop.QuadPart;
508 return hr;
511 static HRESULT media_item_get_stream_type(IMFStreamDescriptor *sd, GUID *major)
513 IMFMediaTypeHandler *handler;
514 HRESULT hr;
516 if (SUCCEEDED(hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler)))
518 hr = IMFMediaTypeHandler_GetMajorType(handler, major);
519 IMFMediaTypeHandler_Release(handler);
522 return hr;
525 static HRESULT media_item_has_stream(struct media_item *item, const GUID *major, BOOL *has_stream, BOOL *is_selected)
527 IMFStreamDescriptor *sd;
528 unsigned int idx = 0;
529 BOOL selected;
530 GUID guid;
532 *has_stream = *is_selected = FALSE;
534 while (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, idx++, &selected, &sd)))
536 if (SUCCEEDED(media_item_get_stream_type(sd, &guid)) && IsEqualGUID(&guid, major))
538 *has_stream = TRUE;
539 *is_selected = selected;
542 IMFStreamDescriptor_Release(sd);
544 if (*has_stream && *is_selected)
545 break;
548 return S_OK;
551 static HRESULT WINAPI media_item_HasVideo(IMFPMediaItem *iface, BOOL *has_video, BOOL *selected)
553 struct media_item *item = impl_from_IMFPMediaItem(iface);
555 TRACE("%p, %p, %p.\n", iface, has_video, selected);
557 return media_item_has_stream(item, &MFMediaType_Video, has_video, selected);
560 static HRESULT WINAPI media_item_HasAudio(IMFPMediaItem *iface, BOOL *has_audio, BOOL *selected)
562 struct media_item *item = impl_from_IMFPMediaItem(iface);
564 TRACE("%p, %p, %p.\n", iface, has_audio, selected);
566 return media_item_has_stream(item, &MFMediaType_Audio, has_audio, selected);
569 static HRESULT WINAPI media_item_IsProtected(IMFPMediaItem *iface, BOOL *protected)
571 struct media_item *item = impl_from_IMFPMediaItem(iface);
573 TRACE("%p, %p.\n", iface, protected);
575 *protected = MFRequireProtectedEnvironment(item->pd) == S_OK;
577 return S_OK;
580 static HRESULT WINAPI media_item_GetDuration(IMFPMediaItem *iface, REFGUID format, PROPVARIANT *value)
582 struct media_item *item = impl_from_IMFPMediaItem(iface);
584 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), value);
586 return IMFPresentationDescriptor_GetItem(item->pd, &MF_PD_DURATION, value);
589 static HRESULT WINAPI media_item_GetNumberOfStreams(IMFPMediaItem *iface, DWORD *count)
591 struct media_item *item = impl_from_IMFPMediaItem(iface);
593 TRACE("%p, %p.\n", iface, count);
595 return IMFPresentationDescriptor_GetStreamDescriptorCount(item->pd, count);
598 static HRESULT WINAPI media_item_GetStreamSelection(IMFPMediaItem *iface, DWORD index, BOOL *selected)
600 struct media_item *item = impl_from_IMFPMediaItem(iface);
601 IMFStreamDescriptor *sd;
602 HRESULT hr;
604 TRACE("%p, %u, %p.\n", iface, index, selected);
606 if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, index, selected, &sd)))
607 IMFStreamDescriptor_Release(sd);
609 return hr;
612 static HRESULT WINAPI media_item_SetStreamSelection(IMFPMediaItem *iface, DWORD index, BOOL select)
614 struct media_item *item = impl_from_IMFPMediaItem(iface);
616 TRACE("%p, %u, %d.\n", iface, index, select);
618 return select ? IMFPresentationDescriptor_SelectStream(item->pd, index) :
619 IMFPresentationDescriptor_DeselectStream(item->pd, index);
622 static HRESULT WINAPI media_item_GetStreamAttribute(IMFPMediaItem *iface, DWORD index, REFGUID key,
623 PROPVARIANT *value)
625 struct media_item *item = impl_from_IMFPMediaItem(iface);
626 IMFStreamDescriptor *sd;
627 BOOL selected;
628 HRESULT hr;
630 TRACE("%p, %u, %s, %p.\n", iface, index, debugstr_guid(key), value);
632 if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, index, &selected, &sd)))
634 hr = IMFStreamDescriptor_GetItem(sd, key, value);
635 IMFStreamDescriptor_Release(sd);
638 return hr;
641 static HRESULT WINAPI media_item_GetPresentationAttribute(IMFPMediaItem *iface, REFGUID key,
642 PROPVARIANT *value)
644 struct media_item *item = impl_from_IMFPMediaItem(iface);
646 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
648 return IMFPresentationDescriptor_GetItem(item->pd, key, value);
651 static HRESULT WINAPI media_item_GetCharacteristics(IMFPMediaItem *iface, MFP_MEDIAITEM_CHARACTERISTICS *flags)
653 struct media_item *item = impl_from_IMFPMediaItem(iface);
654 HRESULT hr;
656 TRACE("%p, %p.\n", iface, flags);
658 *flags = 0;
660 if (SUCCEEDED(hr = IMFMediaSource_GetCharacteristics(item->source, flags)))
662 *flags &= (MFP_MEDIAITEM_IS_LIVE | MFP_MEDIAITEM_CAN_SEEK |
663 MFP_MEDIAITEM_CAN_PAUSE | MFP_MEDIAITEM_HAS_SLOW_SEEK);
666 return hr;
669 static HRESULT WINAPI media_item_SetStreamSink(IMFPMediaItem *iface, DWORD index, IUnknown *sink)
671 struct media_item *item = impl_from_IMFPMediaItem(iface);
672 IMFStreamDescriptor *sd;
673 IUnknown *sink_object;
674 BOOL selected;
675 HRESULT hr;
677 TRACE("%p, %u, %p.\n", iface, index, sink);
679 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, index, &selected, &sd)))
680 return hr;
682 if (sink)
684 if (FAILED(hr = IUnknown_QueryInterface(sink, &IID_IMFStreamSink, (void **)&sink_object)))
685 hr = IUnknown_QueryInterface(sink, &IID_IMFActivate, (void **)&sink_object);
687 if (sink_object)
689 hr = IMFStreamDescriptor_SetUnknown(sd, &_MF_CUSTOM_SINK, sink_object);
690 IUnknown_Release(sink_object);
693 else
694 IMFStreamDescriptor_DeleteItem(sd, &_MF_CUSTOM_SINK);
696 IMFStreamDescriptor_Release(sd);
698 return hr;
701 static HRESULT WINAPI media_item_GetMetadata(IMFPMediaItem *iface, IPropertyStore **metadata)
703 struct media_item *item = impl_from_IMFPMediaItem(iface);
705 TRACE("%p, %p.\n", iface, metadata);
707 return MFGetService((IUnknown *)item->source, &MF_PROPERTY_HANDLER_SERVICE,
708 &IID_IPropertyStore, (void **)&metadata);
711 static const IMFPMediaItemVtbl media_item_vtbl =
713 media_item_QueryInterface,
714 media_item_AddRef,
715 media_item_Release,
716 media_item_GetMediaPlayer,
717 media_item_GetURL,
718 media_item_GetObject,
719 media_item_GetUserData,
720 media_item_SetUserData,
721 media_item_GetStartStopPosition,
722 media_item_SetStartStopPosition,
723 media_item_HasVideo,
724 media_item_HasAudio,
725 media_item_IsProtected,
726 media_item_GetDuration,
727 media_item_GetNumberOfStreams,
728 media_item_GetStreamSelection,
729 media_item_SetStreamSelection,
730 media_item_GetStreamAttribute,
731 media_item_GetPresentationAttribute,
732 media_item_GetCharacteristics,
733 media_item_SetStreamSink,
734 media_item_GetMetadata,
737 static struct media_item *unsafe_impl_from_IMFPMediaItem(IMFPMediaItem *iface)
739 if (!iface)
740 return NULL;
741 assert(iface->lpVtbl == (IMFPMediaItemVtbl *)&media_item_vtbl);
742 return CONTAINING_RECORD(iface, struct media_item, IMFPMediaItem_iface);
745 static HRESULT create_media_item(IMFPMediaPlayer *player, DWORD_PTR user_data, struct media_item **item)
747 struct media_item *object;
749 if (!(object = calloc(1, sizeof(*object))))
750 return E_OUTOFMEMORY;
752 object->IMFPMediaItem_iface.lpVtbl = &media_item_vtbl;
753 object->refcount = 1;
754 object->user_data = user_data;
755 object->player = player;
756 IMFPMediaPlayer_AddRef(object->player);
758 *item = object;
760 return S_OK;
763 static HRESULT media_item_set_source(struct media_item *item, IUnknown *object)
765 IMFPresentationDescriptor *pd;
766 IMFMediaSource *source;
767 HRESULT hr;
769 if (FAILED(hr = IUnknown_QueryInterface(object, &IID_IMFMediaSource, (void **)&source)))
770 return hr;
772 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd)))
774 WARN("Failed to get presentation descriptor, hr %#x.\n", hr);
775 IMFMediaSource_Release(source);
776 return hr;
779 item->source = source;
780 item->pd = pd;
782 return hr;
785 static void media_player_queue_event(struct media_player *player, struct media_event *event)
787 if (player->options & MFP_OPTION_FREE_THREADED_CALLBACK)
789 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, &player->events_callback, &event->IUnknown_iface);
791 else
793 IUnknown_AddRef(&event->IUnknown_iface);
794 PostMessageW(player->event_window, WM_USER, 0, (LPARAM)event);
798 static HRESULT WINAPI media_player_QueryInterface(IMFPMediaPlayer *iface, REFIID riid, void **obj)
800 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
802 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
804 if (IsEqualIID(riid, &IID_IMFPMediaPlayer) ||
805 IsEqualIID(riid, &IID_IUnknown))
807 *obj = &player->IMFPMediaPlayer_iface;
809 else if (IsEqualIID(riid, &IID_IPropertyStore))
811 *obj = &player->IPropertyStore_iface;
813 else
815 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
816 *obj = NULL;
818 return E_NOINTERFACE;
821 IUnknown_AddRef((IUnknown *)*obj);
822 return S_OK;
825 static ULONG WINAPI media_player_AddRef(IMFPMediaPlayer *iface)
827 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
828 ULONG refcount = InterlockedIncrement(&player->refcount);
830 TRACE("%p, refcount %u.\n", iface, refcount);
832 return refcount;
835 static ULONG WINAPI media_player_Release(IMFPMediaPlayer *iface)
837 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
838 ULONG refcount = InterlockedDecrement(&player->refcount);
840 TRACE("%p, refcount %u.\n", iface, refcount);
842 if (!refcount)
844 if (player->callback)
845 IMFPMediaPlayerCallback_Release(player->callback);
846 if (player->propstore)
847 IPropertyStore_Release(player->propstore);
848 if (player->resolver)
849 IMFSourceResolver_Release(player->resolver);
850 if (player->session)
851 IMFMediaSession_Release(player->session);
852 DestroyWindow(player->event_window);
853 DeleteCriticalSection(&player->cs);
854 free(player);
856 platform_shutdown();
859 return refcount;
862 static HRESULT WINAPI media_player_Play(IMFPMediaPlayer *iface)
864 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
865 PROPVARIANT pos;
867 TRACE("%p.\n", iface);
869 pos.vt = VT_EMPTY;
870 return IMFMediaSession_Start(player->session, &GUID_NULL, &pos);
873 static HRESULT WINAPI media_player_Pause(IMFPMediaPlayer *iface)
875 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
877 TRACE("%p.\n", iface);
879 return IMFMediaSession_Pause(player->session);
882 static HRESULT WINAPI media_player_Stop(IMFPMediaPlayer *iface)
884 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
886 TRACE("%p.\n", iface);
888 return IMFMediaSession_Stop(player->session);
891 static HRESULT WINAPI media_player_FrameStep(IMFPMediaPlayer *iface)
893 FIXME("%p.\n", iface);
895 return E_NOTIMPL;
898 static HRESULT WINAPI media_player_SetPosition(IMFPMediaPlayer *iface, REFGUID postype, const PROPVARIANT *position)
900 FIXME("%p, %s, %p.\n", iface, debugstr_guid(postype), position);
902 return E_NOTIMPL;
905 static HRESULT WINAPI media_player_GetPosition(IMFPMediaPlayer *iface, REFGUID postype, PROPVARIANT *position)
907 FIXME("%p, %s, %p.\n", iface, debugstr_guid(postype), position);
909 return E_NOTIMPL;
912 static HRESULT WINAPI media_player_GetDuration(IMFPMediaPlayer *iface, REFGUID postype, PROPVARIANT *position)
914 FIXME("%p, %s, %p.\n", iface, debugstr_guid(postype), position);
916 return E_NOTIMPL;
919 static HRESULT WINAPI media_player_SetRate(IMFPMediaPlayer *iface, float rate)
921 FIXME("%p, %f.\n", iface, rate);
923 return E_NOTIMPL;
926 static HRESULT WINAPI media_player_GetRate(IMFPMediaPlayer *iface, float *rate)
928 FIXME("%p, %p.\n", iface, rate);
930 return E_NOTIMPL;
933 static HRESULT WINAPI media_player_GetSupportedRates(IMFPMediaPlayer *iface, BOOL forward,
934 float *slowest_rate, float *fastest_rate)
936 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
937 IMFRateSupport *rs;
938 HRESULT hr;
940 TRACE("%p, %d, %p, %p.\n", iface, forward, slowest_rate, fastest_rate);
942 if (SUCCEEDED(hr = MFGetService((IUnknown *)player->session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rs)))
944 if (SUCCEEDED(hr = IMFRateSupport_GetSlowestRate(rs, forward ? MFRATE_FORWARD : MFRATE_REVERSE, FALSE, slowest_rate)))
945 hr = IMFRateSupport_GetFastestRate(rs, forward ? MFRATE_FORWARD : MFRATE_REVERSE, FALSE, fastest_rate);
946 IMFRateSupport_Release(rs);
949 return hr;
952 static HRESULT WINAPI media_player_GetState(IMFPMediaPlayer *iface, MFP_MEDIAPLAYER_STATE *state)
954 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
956 TRACE("%p, %p.\n", iface, state);
958 *state = player->state;
960 return S_OK;
963 static HRESULT media_player_create_item_from_url(struct media_player *player,
964 const WCHAR *url, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **ret)
966 struct media_item *item;
967 MF_OBJECT_TYPE obj_type;
968 IUnknown *object;
969 HRESULT hr;
971 *ret = NULL;
973 if (FAILED(hr = create_media_item(&player->IMFPMediaPlayer_iface, user_data, &item)))
974 return hr;
976 if (url && !(item->url = wcsdup(url)))
978 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
979 return E_OUTOFMEMORY;
982 if (sync)
984 if (SUCCEEDED(hr = IMFSourceResolver_CreateObjectFromURL(player->resolver, url, MF_RESOLUTION_MEDIASOURCE,
985 player->propstore, &obj_type, &object)))
987 hr = media_item_set_source(item, object);
988 IUnknown_Release(object);
991 if (SUCCEEDED(hr))
993 *ret = &item->IMFPMediaItem_iface;
994 IMFPMediaItem_AddRef(*ret);
997 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
999 return hr;
1001 else
1003 hr = IMFSourceResolver_BeginCreateObjectFromURL(player->resolver, url, MF_RESOLUTION_MEDIASOURCE,
1004 player->propstore, NULL, &player->resolver_callback, (IUnknown *)&item->IMFPMediaItem_iface);
1006 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
1009 return hr;
1012 static HRESULT WINAPI media_player_CreateMediaItemFromURL(IMFPMediaPlayer *iface,
1013 const WCHAR *url, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **item)
1015 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1016 HRESULT hr;
1018 TRACE("%p, %s, %d, %lx, %p.\n", iface, debugstr_w(url), sync, user_data, item);
1020 EnterCriticalSection(&player->cs);
1021 if (player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
1022 hr = MF_E_SHUTDOWN;
1023 else
1024 hr = media_player_create_item_from_url(player, url, sync, user_data, item);
1025 LeaveCriticalSection(&player->cs);
1027 return hr;
1030 static HRESULT media_player_create_item_from_object(struct media_player *player,
1031 IUnknown *object, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **ret)
1033 struct media_item *item;
1034 MF_OBJECT_TYPE obj_type;
1035 HRESULT hr;
1036 IMFByteStream *stream = NULL;
1037 IMFMediaSource *source = NULL;
1039 *ret = NULL;
1041 if (FAILED(hr = create_media_item(&player->IMFPMediaPlayer_iface, user_data, &item)))
1042 return hr;
1044 item->object = object;
1045 IUnknown_AddRef(item->object);
1047 if (FAILED(IUnknown_QueryInterface(object, &IID_IMFMediaSource, (void **)&source)))
1048 IUnknown_QueryInterface(object, &IID_IMFByteStream, (void **)&stream);
1050 if (!source && !stream)
1052 WARN("Unsupported object type.\n");
1053 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
1054 return E_UNEXPECTED;
1057 if (sync)
1059 if (stream)
1060 hr = IMFSourceResolver_CreateObjectFromByteStream(player->resolver, stream, NULL,
1061 MF_RESOLUTION_MEDIASOURCE, player->propstore, &obj_type, &object);
1062 else
1063 IUnknown_AddRef(object);
1065 if (SUCCEEDED(hr))
1066 hr = media_item_set_source(item, object);
1068 IUnknown_Release(object);
1070 if (SUCCEEDED(hr))
1072 *ret = &item->IMFPMediaItem_iface;
1073 IMFPMediaItem_AddRef(*ret);
1076 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
1078 else
1080 if (stream)
1082 hr = IMFSourceResolver_BeginCreateObjectFromByteStream(player->resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE,
1083 player->propstore, NULL, &player->resolver_callback, (IUnknown *)&item->IMFPMediaItem_iface);
1085 else
1087 /* Resolver callback will check again if item's object is a source. */
1088 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, &player->resolver_callback,
1089 (IUnknown *)&item->IMFPMediaItem_iface);
1092 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
1095 if (source)
1096 IMFMediaSource_Release(source);
1097 if (stream)
1098 IMFByteStream_Release(stream);
1100 return hr;
1103 static HRESULT WINAPI media_player_CreateMediaItemFromObject(IMFPMediaPlayer *iface,
1104 IUnknown *object, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **item)
1106 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1107 HRESULT hr;
1109 TRACE("%p, %p, %d, %lx, %p.\n", iface, object, sync, user_data, item);
1111 EnterCriticalSection(&player->cs);
1112 if (player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
1113 hr = MF_E_SHUTDOWN;
1114 else
1115 hr = media_player_create_item_from_object(player, object, sync, user_data, item);
1116 LeaveCriticalSection(&player->cs);
1118 return hr;
1121 static HRESULT media_item_create_source_node(struct media_item *item, IMFStreamDescriptor *sd,
1122 IMFTopologyNode **node)
1124 HRESULT hr;
1126 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, node)))
1128 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_SOURCE, (IUnknown *)item->source);
1129 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)item->pd);
1130 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd);
1133 return hr;
1136 static HRESULT media_item_create_sink_node(IUnknown *sink, IMFTopologyNode **node)
1138 HRESULT hr;
1140 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, node)))
1141 IMFTopologyNode_SetObject(*node, sink);
1143 return hr;
1146 static HRESULT media_item_create_topology(struct media_player *player, struct media_item *item, IMFTopology **out)
1148 IMFTopologyNode *src_node, *sink_node;
1149 BOOL selected, video_added = FALSE;
1150 IMFStreamDescriptor *sd;
1151 IMFTopology *topology;
1152 unsigned int idx;
1153 IUnknown *sink;
1154 HRESULT hr;
1155 GUID major;
1157 if (FAILED(hr = MFCreateTopology(&topology)))
1158 return hr;
1160 /* Set up branches for all selected streams. */
1162 idx = 0;
1163 while (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, idx++, &selected, &sd)))
1165 if (!selected || FAILED(media_item_get_stream_type(sd, &major)))
1167 IMFStreamDescriptor_Release(sd);
1168 continue;
1171 sink = NULL;
1173 if (SUCCEEDED(IMFStreamDescriptor_GetUnknown(sd, &_MF_CUSTOM_SINK, &IID_IUnknown, (void **)&sink)))
1175 /* User sink is attached as-is. */
1177 else if (IsEqualGUID(&major, &MFMediaType_Audio))
1179 if (FAILED(hr = MFCreateAudioRendererActivate((IMFActivate **)&sink)))
1180 WARN("Failed to create SAR activation object, hr %#x.\n", hr);
1182 else if (IsEqualGUID(&major, &MFMediaType_Video) && player->output_window && !video_added)
1184 if (FAILED(hr = MFCreateVideoRendererActivate(player->output_window, (IMFActivate **)&sink)))
1185 WARN("Failed to create EVR activation object, hr %#x.\n", hr);
1186 video_added = SUCCEEDED(hr);
1189 if (sink)
1191 hr = media_item_create_source_node(item, sd, &src_node);
1192 if (SUCCEEDED(hr))
1193 hr = media_item_create_sink_node(sink, &sink_node);
1195 if (SUCCEEDED(hr))
1197 IMFTopology_AddNode(topology, src_node);
1198 IMFTopology_AddNode(topology, sink_node);
1199 IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0);
1202 if (src_node)
1203 IMFTopologyNode_Release(src_node);
1204 if (sink_node)
1205 IMFTopologyNode_Release(sink_node);
1207 IUnknown_Release(sink);
1210 IMFStreamDescriptor_Release(sd);
1213 IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, TRUE);
1215 *out = topology;
1217 return S_OK;
1220 static HRESULT WINAPI media_player_SetMediaItem(IMFPMediaPlayer *iface, IMFPMediaItem *item_iface)
1222 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1223 struct media_item *item = unsafe_impl_from_IMFPMediaItem(item_iface);
1224 IMFTopology *topology;
1225 HRESULT hr;
1227 TRACE("%p, %p.\n", iface, item_iface);
1229 if (item->player != iface)
1230 return E_INVALIDARG;
1232 if (FAILED(hr = media_item_create_topology(player, item, &topology)))
1233 return hr;
1235 IMFTopology_SetUnknown(topology, &_MF_TOPO_MEDIA_ITEM, (IUnknown *)item_iface);
1236 hr = IMFMediaSession_SetTopology(player->session, MFSESSION_SETTOPOLOGY_IMMEDIATE, topology);
1237 IMFTopology_Release(topology);
1239 return hr;
1242 static HRESULT WINAPI media_player_ClearMediaItem(IMFPMediaPlayer *iface)
1244 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1246 TRACE("%p.\n", iface);
1248 return IMFMediaSession_SetTopology(player->session, MFSESSION_SETTOPOLOGY_CLEAR_CURRENT, NULL);
1251 static HRESULT WINAPI media_player_GetMediaItem(IMFPMediaPlayer *iface, IMFPMediaItem **item)
1253 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1254 HRESULT hr = S_OK;
1256 TRACE("%p, %p.\n", iface, item);
1258 if (!item)
1259 return E_POINTER;
1261 EnterCriticalSection(&player->cs);
1262 if (player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
1263 hr = MF_E_SHUTDOWN;
1264 else if (!player->item)
1265 hr = MF_E_NOT_FOUND;
1266 else
1268 *item = player->item;
1269 IMFPMediaItem_AddRef(player->item);
1271 LeaveCriticalSection(&player->cs);
1273 return hr;
1276 static HRESULT WINAPI media_player_GetVolume(IMFPMediaPlayer *iface, float *volume)
1278 FIXME("%p, %p.\n", iface, volume);
1280 return E_NOTIMPL;
1283 static HRESULT WINAPI media_player_SetVolume(IMFPMediaPlayer *iface, float volume)
1285 FIXME("%p, %.8e.\n", iface, volume);
1287 return E_NOTIMPL;
1290 static HRESULT WINAPI media_player_GetBalance(IMFPMediaPlayer *iface, float *balance)
1292 FIXME("%p, %p.\n", iface, balance);
1294 return E_NOTIMPL;
1297 static HRESULT WINAPI media_player_SetBalance(IMFPMediaPlayer *iface, float balance)
1299 FIXME("%p, %.8e.\n", iface, balance);
1301 return E_NOTIMPL;
1304 static HRESULT WINAPI media_player_GetMute(IMFPMediaPlayer *iface, BOOL *mute)
1306 FIXME("%p, %p.\n", iface, mute);
1308 return E_NOTIMPL;
1311 static HRESULT WINAPI media_player_SetMute(IMFPMediaPlayer *iface, BOOL mute)
1313 FIXME("%p, %d.\n", iface, mute);
1315 return E_NOTIMPL;
1318 static HRESULT WINAPI media_player_GetNativeVideoSize(IMFPMediaPlayer *iface,
1319 SIZE *video, SIZE *arvideo)
1321 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1322 IMFVideoDisplayControl *display_control;
1323 HRESULT hr;
1325 TRACE("%p, %p, %p.\n", iface, video, arvideo);
1327 if (SUCCEEDED(hr = MFGetService((IUnknown *)player->session, &MR_VIDEO_RENDER_SERVICE,
1328 &IID_IMFVideoDisplayControl, (void **)&display_control)))
1330 hr = IMFVideoDisplayControl_GetNativeVideoSize(display_control, video, arvideo);
1331 IMFVideoDisplayControl_Release(display_control);
1334 return hr;
1337 static HRESULT WINAPI media_player_GetIdealVideoSize(IMFPMediaPlayer *iface,
1338 SIZE *min_size, SIZE *max_size)
1340 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1341 IMFVideoDisplayControl *display_control;
1342 HRESULT hr;
1344 TRACE("%p, %p, %p.\n", iface, min_size, max_size);
1346 if (SUCCEEDED(hr = MFGetService((IUnknown *)player->session, &MR_VIDEO_RENDER_SERVICE,
1347 &IID_IMFVideoDisplayControl, (void **)&display_control)))
1349 hr = IMFVideoDisplayControl_GetIdealVideoSize(display_control, min_size, max_size);
1350 IMFVideoDisplayControl_Release(display_control);
1353 return hr;
1356 static HRESULT WINAPI media_player_SetVideoSourceRect(IMFPMediaPlayer *iface,
1357 MFVideoNormalizedRect const *rect)
1359 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1360 IMFVideoDisplayControl *display_control;
1361 HRESULT hr;
1363 TRACE("%p, %p.\n", iface, rect);
1365 if (SUCCEEDED(hr = MFGetService((IUnknown *)player->session, &MR_VIDEO_RENDER_SERVICE,
1366 &IID_IMFVideoDisplayControl, (void **)&display_control)))
1368 hr = IMFVideoDisplayControl_SetVideoPosition(display_control, rect, NULL);
1369 IMFVideoDisplayControl_Release(display_control);
1372 return hr;
1375 static HRESULT WINAPI media_player_GetVideoSourceRect(IMFPMediaPlayer *iface,
1376 MFVideoNormalizedRect *rect)
1378 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1379 IMFVideoDisplayControl *display_control;
1380 HRESULT hr;
1381 RECT dest;
1383 TRACE("%p, %p.\n", iface, rect);
1385 if (SUCCEEDED(hr = MFGetService((IUnknown *)player->session, &MR_VIDEO_RENDER_SERVICE,
1386 &IID_IMFVideoDisplayControl, (void **)&display_control)))
1388 hr = IMFVideoDisplayControl_GetVideoPosition(display_control, rect, &dest);
1389 IMFVideoDisplayControl_Release(display_control);
1392 return hr;
1395 static HRESULT WINAPI media_player_SetAspectRatioMode(IMFPMediaPlayer *iface, DWORD mode)
1397 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1398 IMFVideoDisplayControl *display_control;
1399 HRESULT hr;
1401 TRACE("%p, %u.\n", iface, mode);
1403 if (SUCCEEDED(hr = MFGetService((IUnknown *)player->session, &MR_VIDEO_RENDER_SERVICE,
1404 &IID_IMFVideoDisplayControl, (void **)&display_control)))
1406 hr = IMFVideoDisplayControl_SetAspectRatioMode(display_control, mode);
1407 IMFVideoDisplayControl_Release(display_control);
1410 return hr;
1413 static HRESULT WINAPI media_player_GetAspectRatioMode(IMFPMediaPlayer *iface,
1414 DWORD *mode)
1416 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1417 IMFVideoDisplayControl *display_control;
1418 HRESULT hr;
1420 TRACE("%p, %p.\n", iface, mode);
1422 if (SUCCEEDED(hr = MFGetService((IUnknown *)player->session, &MR_VIDEO_RENDER_SERVICE,
1423 &IID_IMFVideoDisplayControl, (void **)&display_control)))
1425 hr = IMFVideoDisplayControl_GetAspectRatioMode(display_control, mode);
1426 IMFVideoDisplayControl_Release(display_control);
1429 return hr;
1432 static HRESULT WINAPI media_player_GetVideoWindow(IMFPMediaPlayer *iface, HWND *window)
1434 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1436 TRACE("%p, %p.\n", iface, window);
1438 *window = player->output_window;
1440 return S_OK;
1443 static HRESULT WINAPI media_player_UpdateVideo(IMFPMediaPlayer *iface)
1445 FIXME("%p.\n", iface);
1447 return E_NOTIMPL;
1450 static HRESULT WINAPI media_player_SetBorderColor(IMFPMediaPlayer *iface, COLORREF color)
1452 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1453 IMFVideoDisplayControl *display_control;
1454 HRESULT hr;
1456 TRACE("%p, %#x.\n", iface, color);
1458 if (SUCCEEDED(hr = MFGetService((IUnknown *)player->session, &MR_VIDEO_RENDER_SERVICE,
1459 &IID_IMFVideoDisplayControl, (void **)&display_control)))
1461 hr = IMFVideoDisplayControl_SetBorderColor(display_control, color);
1462 IMFVideoDisplayControl_Release(display_control);
1465 return hr;
1468 static HRESULT WINAPI media_player_GetBorderColor(IMFPMediaPlayer *iface, COLORREF *color)
1470 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1471 IMFVideoDisplayControl *display_control;
1472 HRESULT hr;
1474 TRACE("%p, %p.\n", iface, color);
1476 if (SUCCEEDED(hr = MFGetService((IUnknown *)player->session, &MR_VIDEO_RENDER_SERVICE,
1477 &IID_IMFVideoDisplayControl, (void **)&display_control)))
1479 hr = IMFVideoDisplayControl_GetBorderColor(display_control, color);
1480 IMFVideoDisplayControl_Release(display_control);
1483 return hr;
1486 static HRESULT WINAPI media_player_InsertEffect(IMFPMediaPlayer *iface, IUnknown *effect,
1487 BOOL optional)
1489 FIXME("%p, %p, %d.\n", iface, effect, optional);
1491 return E_NOTIMPL;
1494 static HRESULT WINAPI media_player_RemoveEffect(IMFPMediaPlayer *iface, IUnknown *effect)
1496 FIXME("%p, %p.\n", iface, effect);
1498 return E_NOTIMPL;
1501 static HRESULT WINAPI media_player_RemoveAllEffects(IMFPMediaPlayer *iface)
1503 FIXME("%p.\n", iface);
1505 return E_NOTIMPL;
1508 static HRESULT WINAPI media_player_Shutdown(IMFPMediaPlayer *iface)
1510 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1512 TRACE("%p.\n", iface);
1514 EnterCriticalSection(&player->cs);
1515 media_player_set_state(player, MFP_MEDIAPLAYER_STATE_SHUTDOWN);
1516 if (player->item)
1518 IMFPMediaItem_Release(player->item);
1519 player->item = NULL;
1521 LeaveCriticalSection(&player->cs);
1523 return S_OK;
1526 static const IMFPMediaPlayerVtbl media_player_vtbl =
1528 media_player_QueryInterface,
1529 media_player_AddRef,
1530 media_player_Release,
1531 media_player_Play,
1532 media_player_Pause,
1533 media_player_Stop,
1534 media_player_FrameStep,
1535 media_player_SetPosition,
1536 media_player_GetPosition,
1537 media_player_GetDuration,
1538 media_player_SetRate,
1539 media_player_GetRate,
1540 media_player_GetSupportedRates,
1541 media_player_GetState,
1542 media_player_CreateMediaItemFromURL,
1543 media_player_CreateMediaItemFromObject,
1544 media_player_SetMediaItem,
1545 media_player_ClearMediaItem,
1546 media_player_GetMediaItem,
1547 media_player_GetVolume,
1548 media_player_SetVolume,
1549 media_player_GetBalance,
1550 media_player_SetBalance,
1551 media_player_GetMute,
1552 media_player_SetMute,
1553 media_player_GetNativeVideoSize,
1554 media_player_GetIdealVideoSize,
1555 media_player_SetVideoSourceRect,
1556 media_player_GetVideoSourceRect,
1557 media_player_SetAspectRatioMode,
1558 media_player_GetAspectRatioMode,
1559 media_player_GetVideoWindow,
1560 media_player_UpdateVideo,
1561 media_player_SetBorderColor,
1562 media_player_GetBorderColor,
1563 media_player_InsertEffect,
1564 media_player_RemoveEffect,
1565 media_player_RemoveAllEffects,
1566 media_player_Shutdown,
1569 static HRESULT WINAPI media_player_propstore_QueryInterface(IPropertyStore *iface,
1570 REFIID riid, void **obj)
1572 struct media_player *player = impl_from_IPropertyStore(iface);
1573 return IMFPMediaPlayer_QueryInterface(&player->IMFPMediaPlayer_iface, riid, obj);
1576 static ULONG WINAPI media_player_propstore_AddRef(IPropertyStore *iface)
1578 struct media_player *player = impl_from_IPropertyStore(iface);
1579 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1582 static ULONG WINAPI media_player_propstore_Release(IPropertyStore *iface)
1584 struct media_player *player = impl_from_IPropertyStore(iface);
1585 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1588 static HRESULT WINAPI media_player_propstore_GetCount(IPropertyStore *iface, DWORD *count)
1590 struct media_player *player = impl_from_IPropertyStore(iface);
1592 TRACE("%p, %p.\n", iface, count);
1594 return IPropertyStore_GetCount(player->propstore, count);
1597 static HRESULT WINAPI media_player_propstore_GetAt(IPropertyStore *iface, DWORD prop, PROPERTYKEY *key)
1599 struct media_player *player = impl_from_IPropertyStore(iface);
1601 TRACE("%p, %u, %p.\n", iface, prop, key);
1603 return IPropertyStore_GetAt(player->propstore, prop, key);
1606 static HRESULT WINAPI media_player_propstore_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *value)
1608 struct media_player *player = impl_from_IPropertyStore(iface);
1610 TRACE("%p, %p, %p.\n", iface, key, value);
1612 return IPropertyStore_GetValue(player->propstore, key, value);
1615 static HRESULT WINAPI media_player_propstore_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT value)
1617 struct media_player *player = impl_from_IPropertyStore(iface);
1619 TRACE("%p, %p, %p.\n", iface, key, value);
1621 return IPropertyStore_SetValue(player->propstore, key, value);
1624 static HRESULT WINAPI media_player_propstore_Commit(IPropertyStore *iface)
1626 struct media_player *player = impl_from_IPropertyStore(iface);
1628 TRACE("%p.\n", iface);
1630 return IPropertyStore_Commit(player->propstore);
1633 static const IPropertyStoreVtbl media_player_propstore_vtbl =
1635 media_player_propstore_QueryInterface,
1636 media_player_propstore_AddRef,
1637 media_player_propstore_Release,
1638 media_player_propstore_GetCount,
1639 media_player_propstore_GetAt,
1640 media_player_propstore_GetValue,
1641 media_player_propstore_SetValue,
1642 media_player_propstore_Commit,
1645 static HRESULT WINAPI media_player_callback_QueryInterface(IMFAsyncCallback *iface,
1646 REFIID riid, void **obj)
1648 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
1649 IsEqualIID(riid, &IID_IUnknown))
1651 *obj = iface;
1652 IMFAsyncCallback_AddRef(iface);
1653 return S_OK;
1656 *obj = NULL;
1657 return E_NOINTERFACE;
1660 static ULONG WINAPI media_player_resolver_callback_AddRef(IMFAsyncCallback *iface)
1662 struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
1663 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1666 static ULONG WINAPI media_player_resolver_callback_Release(IMFAsyncCallback *iface)
1668 struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
1669 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1672 static HRESULT WINAPI media_player_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags,
1673 DWORD *queue)
1675 return E_NOTIMPL;
1678 static HRESULT WINAPI media_player_resolver_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1680 struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
1681 struct media_event *event;
1682 IUnknown *object, *state;
1683 MF_OBJECT_TYPE obj_type;
1684 struct media_item *item;
1685 HRESULT hr;
1687 if (FAILED(IMFAsyncResult_GetState(result, &state)))
1688 return S_OK;
1690 item = impl_from_IMFPMediaItem((IMFPMediaItem *)state);
1692 if (item->object)
1694 if (FAILED(hr = IUnknown_QueryInterface(item->object, &IID_IMFMediaSource, (void **)&object)))
1695 hr = IMFSourceResolver_EndCreateObjectFromByteStream(player->resolver, result, &obj_type, &object);
1697 else
1698 hr = IMFSourceResolver_EndCreateObjectFromURL(player->resolver, result, &obj_type, &object);
1700 if (SUCCEEDED(hr))
1702 hr = media_item_set_source(item, object);
1703 IUnknown_Release(object);
1706 if (FAILED(hr))
1707 WARN("Failed to set media source, hr %#x.\n", hr);
1709 if (FAILED(media_event_create(player, MFP_EVENT_TYPE_MEDIAITEM_CREATED, hr,
1710 &item->IMFPMediaItem_iface, &event)))
1712 WARN("Failed to create event object.\n");
1713 IUnknown_Release(state);
1714 return S_OK;
1716 event->u.item_created.dwUserData = item->user_data;
1718 media_player_queue_event(player, event);
1720 IUnknown_Release(&event->IUnknown_iface);
1721 IUnknown_Release(state);
1723 return S_OK;
1726 static const IMFAsyncCallbackVtbl media_player_resolver_callback_vtbl =
1728 media_player_callback_QueryInterface,
1729 media_player_resolver_callback_AddRef,
1730 media_player_resolver_callback_Release,
1731 media_player_callback_GetParameters,
1732 media_player_resolver_callback_Invoke,
1735 static ULONG WINAPI media_player_events_callback_AddRef(IMFAsyncCallback *iface)
1737 struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
1738 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1741 static ULONG WINAPI media_player_events_callback_Release(IMFAsyncCallback *iface)
1743 struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
1744 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1747 static HRESULT WINAPI media_player_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1749 struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
1750 struct media_event *event;
1751 IUnknown *state;
1753 if (FAILED(IMFAsyncResult_GetState(result, &state)))
1754 return S_OK;
1756 event = impl_event_from_IUnknown(state);
1758 if (player->callback)
1759 IMFPMediaPlayerCallback_OnMediaPlayerEvent(player->callback, &event->u.header);
1761 IUnknown_Release(state);
1763 return S_OK;
1766 static const IMFAsyncCallbackVtbl media_player_events_callback_vtbl =
1768 media_player_callback_QueryInterface,
1769 media_player_events_callback_AddRef,
1770 media_player_events_callback_Release,
1771 media_player_callback_GetParameters,
1772 media_player_events_callback_Invoke,
1775 static ULONG WINAPI media_player_session_events_callback_AddRef(IMFAsyncCallback *iface)
1777 struct media_player *player = impl_from_session_events_IMFAsyncCallback(iface);
1778 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1781 static ULONG WINAPI media_player_session_events_callback_Release(IMFAsyncCallback *iface)
1783 struct media_player *player = impl_from_session_events_IMFAsyncCallback(iface);
1784 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1787 static void media_player_change_state(struct media_player *player, MFP_MEDIAPLAYER_STATE state,
1788 HRESULT event_status, struct media_event **event)
1790 MFP_EVENT_TYPE event_type;
1792 EnterCriticalSection(&player->cs);
1794 if (state == MFP_MEDIAPLAYER_STATE_PLAYING)
1795 event_type = MFP_EVENT_TYPE_PLAY;
1796 else if (state == MFP_MEDIAPLAYER_STATE_PAUSED)
1797 event_type = MFP_EVENT_TYPE_PAUSE;
1798 else
1799 event_type = MFP_EVENT_TYPE_STOP;
1801 media_player_set_state(player, state);
1802 media_event_create(player, event_type, event_status, player->item, event);
1804 LeaveCriticalSection(&player->cs);
1807 static void media_player_set_item(struct media_player *player, IMFTopology *topology, HRESULT event_status,
1808 struct media_event **event)
1810 IMFPMediaItem *item;
1812 if (FAILED(IMFTopology_GetUnknown(topology, &_MF_TOPO_MEDIA_ITEM, &IID_IMFPMediaItem, (void **)&item)))
1813 return;
1815 EnterCriticalSection(&player->cs);
1817 if (player->item)
1818 IMFPMediaItem_Release(player->item);
1819 player->item = item;
1820 IMFPMediaItem_AddRef(player->item);
1822 media_event_create(player, MFP_EVENT_TYPE_MEDIAITEM_SET, event_status, item, event);
1824 LeaveCriticalSection(&player->cs);
1826 IMFPMediaItem_Release(item);
1829 static void media_player_clear_item(struct media_player *player, HRESULT event_status,
1830 struct media_event **event)
1832 IMFPMediaItem *item;
1834 EnterCriticalSection(&player->cs);
1836 item = player->item;
1837 player->item = NULL;
1839 media_event_create(player, MFP_EVENT_TYPE_MEDIAITEM_SET, event_status, item, event);
1841 LeaveCriticalSection(&player->cs);
1844 static void media_player_create_forward_event(struct media_player *player, HRESULT event_status, IMFMediaEvent *session_event,
1845 struct media_event **event)
1847 EnterCriticalSection(&player->cs);
1849 if (SUCCEEDED(media_event_create(player, MFP_EVENT_TYPE_MF, event_status, player->item, event)))
1851 IMFMediaEvent_GetType(session_event, &(*event)->u.event.MFEventType);
1852 (*event)->u.event.pMFMediaEvent = session_event;
1853 IMFMediaEvent_AddRef((*event)->u.event.pMFMediaEvent);
1856 LeaveCriticalSection(&player->cs);
1859 static void media_player_create_playback_ended_event(struct media_player *player, HRESULT event_status,
1860 struct media_event **event)
1862 EnterCriticalSection(&player->cs);
1864 if (SUCCEEDED(media_event_create(player, MFP_EVENT_TYPE_PLAYBACK_ENDED, event_status, player->item, event)))
1866 if (player->item)
1867 IMFPMediaItem_Release(player->item);
1868 player->item = NULL;
1871 LeaveCriticalSection(&player->cs);
1874 static HRESULT WINAPI media_player_session_events_callback_Invoke(IMFAsyncCallback *iface,
1875 IMFAsyncResult *result)
1877 struct media_player *player = impl_from_session_events_IMFAsyncCallback(iface);
1878 MediaEventType session_event_type = MEUnknown;
1879 struct media_event *event = NULL;
1880 IMFMediaEvent *session_event;
1881 MFP_MEDIAPLAYER_STATE state;
1882 HRESULT hr, event_status;
1883 IMFPMediaItem *item = NULL;
1884 IMFTopology *topology;
1885 unsigned int status;
1886 PROPVARIANT value;
1888 if (FAILED(hr = IMFMediaSession_EndGetEvent(player->session, result, &session_event)))
1889 return S_OK;
1891 IMFMediaEvent_GetType(session_event, &session_event_type);
1892 IMFMediaEvent_GetStatus(session_event, &event_status);
1894 switch (session_event_type)
1896 case MESessionStarted:
1897 case MESessionStopped:
1898 case MESessionPaused:
1900 if (session_event_type == MESessionStarted)
1901 state = MFP_MEDIAPLAYER_STATE_PLAYING;
1902 else if (session_event_type == MESessionPaused)
1903 state = MFP_MEDIAPLAYER_STATE_PAUSED;
1904 else
1905 state = MFP_MEDIAPLAYER_STATE_STOPPED;
1907 media_player_change_state(player, state, event_status, &event);
1909 break;
1911 case MESessionTopologySet:
1913 value.vt = VT_EMPTY;
1914 if (SUCCEEDED(IMFMediaEvent_GetValue(session_event, &value)))
1916 if (value.vt == VT_EMPTY)
1918 media_player_clear_item(player, event_status, &event);
1920 else if (value.vt == VT_UNKNOWN && value.punkVal &&
1921 SUCCEEDED(IUnknown_QueryInterface(value.punkVal, &IID_IMFTopology, (void **)&topology)))
1923 media_player_set_item(player, topology, event_status, &event);
1924 IMFTopology_Release(topology);
1926 PropVariantClear(&value);
1929 break;
1931 case MESessionTopologyStatus:
1933 if (SUCCEEDED(IMFMediaEvent_GetUINT32(session_event, &MF_EVENT_TOPOLOGY_STATUS, &status)) &&
1934 status == MF_TOPOSTATUS_ENDED)
1936 media_player_create_playback_ended_event(player, event_status, &event);
1939 break;
1941 case MEBufferingStarted:
1942 case MEBufferingStopped:
1943 case MEExtendedType:
1944 case MEReconnectStart:
1945 case MEReconnectEnd:
1946 case MERendererEvent:
1947 case MEStreamSinkFormatChanged:
1949 media_player_create_forward_event(player, event_status, session_event, &event);
1951 break;
1953 case MEError:
1955 media_event_create(player, MFP_EVENT_TYPE_ERROR, event_status, NULL, &event);
1957 break;
1959 default:
1963 if (item)
1964 IMFPMediaItem_Release(item);
1966 if (event)
1968 media_player_queue_event(player, event);
1969 IUnknown_Release(&event->IUnknown_iface);
1972 IMFMediaSession_BeginGetEvent(player->session, &player->session_events_callback, NULL);
1973 IMFMediaEvent_Release(session_event);
1975 return S_OK;
1978 static const IMFAsyncCallbackVtbl media_player_session_events_callback_vtbl =
1980 media_player_callback_QueryInterface,
1981 media_player_session_events_callback_AddRef,
1982 media_player_session_events_callback_Release,
1983 media_player_callback_GetParameters,
1984 media_player_session_events_callback_Invoke,
1987 /***********************************************************************
1988 * MFPCreateMediaPlayer (mfplay.@)
1990 HRESULT WINAPI MFPCreateMediaPlayer(const WCHAR *url, BOOL start_playback, MFP_CREATION_OPTIONS options,
1991 IMFPMediaPlayerCallback *callback, HWND window, IMFPMediaPlayer **player)
1993 struct media_player *object;
1994 IMFPMediaItem *item;
1995 HRESULT hr;
1997 TRACE("%s, %d, %#x, %p, %p, %p.\n", debugstr_w(url), start_playback, options, callback, window, player);
1999 if (!player)
2000 return E_POINTER;
2002 *player = NULL;
2004 if (!url && start_playback)
2005 return E_INVALIDARG;
2007 if (!(object = calloc(1, sizeof(*object))))
2008 return E_OUTOFMEMORY;
2010 platform_startup();
2012 object->IMFPMediaPlayer_iface.lpVtbl = &media_player_vtbl;
2013 object->IPropertyStore_iface.lpVtbl = &media_player_propstore_vtbl;
2014 object->resolver_callback.lpVtbl = &media_player_resolver_callback_vtbl;
2015 object->events_callback.lpVtbl = &media_player_events_callback_vtbl;
2016 object->session_events_callback.lpVtbl = &media_player_session_events_callback_vtbl;
2017 object->refcount = 1;
2018 object->callback = callback;
2019 if (object->callback)
2020 IMFPMediaPlayerCallback_AddRef(object->callback);
2021 object->options = options;
2022 object->output_window = window;
2023 InitializeCriticalSection(&object->cs);
2024 if (FAILED(hr = CreatePropertyStore(&object->propstore)))
2025 goto failed;
2026 if (FAILED(hr = MFCreateSourceResolver(&object->resolver)))
2027 goto failed;
2028 if (FAILED(hr = MFCreateMediaSession(NULL, &object->session)))
2029 goto failed;
2030 if (FAILED(hr = IMFMediaSession_BeginGetEvent(object->session, &object->session_events_callback, NULL)))
2031 goto failed;
2032 if (!(object->options & MFP_OPTION_FREE_THREADED_CALLBACK))
2034 object->event_window = CreateWindowW(eventclassW, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE,
2035 0, mfplay_instance, NULL);
2038 if (url)
2040 if (FAILED(hr = media_player_create_item_from_url(object, url, TRUE, 0, &item)))
2042 WARN("Failed to create media item, hr %#x.\n", hr);
2043 goto failed;
2046 hr = IMFPMediaPlayer_SetMediaItem(&object->IMFPMediaPlayer_iface, item);
2047 IMFPMediaItem_Release(item);
2048 if (FAILED(hr))
2050 WARN("Failed to set media item, hr %#x.\n", hr);
2051 goto failed;
2054 if (start_playback)
2055 IMFPMediaPlayer_Play(&object->IMFPMediaPlayer_iface);
2058 *player = &object->IMFPMediaPlayer_iface;
2060 return S_OK;
2062 failed:
2064 IMFPMediaPlayer_Release(&object->IMFPMediaPlayer_iface);
2066 return hr;
2069 static void media_player_register_window_class(void)
2071 WNDCLASSW cls = { 0 };
2073 cls.lpfnWndProc = media_player_event_proc;
2074 cls.hInstance = mfplay_instance;
2075 cls.lpszClassName = eventclassW;
2077 RegisterClassW(&cls);
2080 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
2082 switch (reason)
2084 case DLL_PROCESS_ATTACH:
2085 mfplay_instance = instance;
2086 DisableThreadLibraryCalls(instance);
2087 media_player_register_window_class();
2088 break;
2089 case DLL_PROCESS_DETACH:
2090 if (reserved) break;
2091 UnregisterClassW(eventclassW, instance);
2092 break;
2095 return TRUE;