mfplay: Implement GetPosition().
[wine.git] / dlls / mfplay / player.c
bloba34973f8e360a4cb5fa97a7aef6f84f5d47ca936
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 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
908 IMFPresentationClock *presentation_clock;
909 IMFClock *clock;
910 HRESULT hr;
912 TRACE("%p, %s, %p.\n", iface, debugstr_guid(postype), position);
914 if (!position)
915 return E_POINTER;
917 if (!IsEqualGUID(postype, &MFP_POSITIONTYPE_100NS))
918 return E_INVALIDARG;
920 EnterCriticalSection(&player->cs);
921 if (player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
922 hr = MF_E_SHUTDOWN;
923 else if (!player->item)
924 hr = MF_E_INVALIDREQUEST;
925 else
927 if (SUCCEEDED(hr = IMFMediaSession_GetClock(player->session, &clock)))
929 if (SUCCEEDED(hr = IMFClock_QueryInterface(clock, &IID_IMFPresentationClock, (void **)&presentation_clock)))
931 position->vt = VT_UI8;
932 hr = IMFPresentationClock_GetTime(presentation_clock, (MFTIME *)&position->uhVal.QuadPart);
933 IMFPresentationClock_Release(presentation_clock);
935 IMFClock_Release(clock);
938 LeaveCriticalSection(&player->cs);
940 return hr;
943 static HRESULT WINAPI media_player_GetDuration(IMFPMediaPlayer *iface, REFGUID postype, PROPVARIANT *duration)
945 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
946 HRESULT hr;
948 TRACE("%p, %s, %p.\n", iface, debugstr_guid(postype), duration);
950 if (!duration)
951 return E_POINTER;
953 if (!IsEqualGUID(postype, &MFP_POSITIONTYPE_100NS))
954 return E_INVALIDARG;
956 EnterCriticalSection(&player->cs);
957 if (player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
958 hr = MF_E_SHUTDOWN;
959 else if (!player->item)
960 hr = MF_E_INVALIDREQUEST;
961 else
962 /* FIXME: use start/stop markers for resulting duration */
963 hr = IMFPMediaItem_GetDuration(player->item, postype, duration);
964 LeaveCriticalSection(&player->cs);
966 return hr;
969 static HRESULT WINAPI media_player_SetRate(IMFPMediaPlayer *iface, float rate)
971 FIXME("%p, %f.\n", iface, rate);
973 return E_NOTIMPL;
976 static HRESULT WINAPI media_player_GetRate(IMFPMediaPlayer *iface, float *rate)
978 FIXME("%p, %p.\n", iface, rate);
980 return E_NOTIMPL;
983 static HRESULT WINAPI media_player_GetSupportedRates(IMFPMediaPlayer *iface, BOOL forward,
984 float *slowest_rate, float *fastest_rate)
986 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
987 IMFRateSupport *rs;
988 HRESULT hr;
990 TRACE("%p, %d, %p, %p.\n", iface, forward, slowest_rate, fastest_rate);
992 if (SUCCEEDED(hr = MFGetService((IUnknown *)player->session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rs)))
994 if (SUCCEEDED(hr = IMFRateSupport_GetSlowestRate(rs, forward ? MFRATE_FORWARD : MFRATE_REVERSE, FALSE, slowest_rate)))
995 hr = IMFRateSupport_GetFastestRate(rs, forward ? MFRATE_FORWARD : MFRATE_REVERSE, FALSE, fastest_rate);
996 IMFRateSupport_Release(rs);
999 return hr;
1002 static HRESULT WINAPI media_player_GetState(IMFPMediaPlayer *iface, MFP_MEDIAPLAYER_STATE *state)
1004 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1006 TRACE("%p, %p.\n", iface, state);
1008 *state = player->state;
1010 return S_OK;
1013 static HRESULT media_player_create_item_from_url(struct media_player *player,
1014 const WCHAR *url, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **ret)
1016 struct media_item *item;
1017 MF_OBJECT_TYPE obj_type;
1018 IUnknown *object;
1019 HRESULT hr;
1021 if (FAILED(hr = create_media_item(&player->IMFPMediaPlayer_iface, user_data, &item)))
1022 return hr;
1024 if (url && !(item->url = wcsdup(url)))
1026 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
1027 return E_OUTOFMEMORY;
1030 if (sync)
1032 if (!ret)
1033 return E_POINTER;
1035 *ret = NULL;
1037 if (SUCCEEDED(hr = IMFSourceResolver_CreateObjectFromURL(player->resolver, url, MF_RESOLUTION_MEDIASOURCE,
1038 player->propstore, &obj_type, &object)))
1040 hr = media_item_set_source(item, object);
1041 IUnknown_Release(object);
1044 if (SUCCEEDED(hr))
1046 *ret = &item->IMFPMediaItem_iface;
1047 IMFPMediaItem_AddRef(*ret);
1050 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
1052 return hr;
1054 else
1056 if (!player->callback)
1058 WARN("Asynchronous item creation is not supported without user callback.\n");
1059 return MF_E_INVALIDREQUEST;
1062 if (ret) *ret = NULL;
1064 hr = IMFSourceResolver_BeginCreateObjectFromURL(player->resolver, url, MF_RESOLUTION_MEDIASOURCE,
1065 player->propstore, NULL, &player->resolver_callback, (IUnknown *)&item->IMFPMediaItem_iface);
1067 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
1070 return hr;
1073 static HRESULT WINAPI media_player_CreateMediaItemFromURL(IMFPMediaPlayer *iface,
1074 const WCHAR *url, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **item)
1076 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1077 HRESULT hr;
1079 TRACE("%p, %s, %d, %lx, %p.\n", iface, debugstr_w(url), sync, user_data, item);
1081 EnterCriticalSection(&player->cs);
1082 if (player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
1083 hr = MF_E_SHUTDOWN;
1084 else
1085 hr = media_player_create_item_from_url(player, url, sync, user_data, item);
1086 LeaveCriticalSection(&player->cs);
1088 return hr;
1091 static HRESULT media_player_create_item_from_object(struct media_player *player,
1092 IUnknown *object, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **ret)
1094 struct media_item *item;
1095 MF_OBJECT_TYPE obj_type;
1096 HRESULT hr;
1097 IMFByteStream *stream = NULL;
1098 IMFMediaSource *source = NULL;
1100 *ret = NULL;
1102 if (FAILED(hr = create_media_item(&player->IMFPMediaPlayer_iface, user_data, &item)))
1103 return hr;
1105 item->object = object;
1106 IUnknown_AddRef(item->object);
1108 if (FAILED(IUnknown_QueryInterface(object, &IID_IMFMediaSource, (void **)&source)))
1109 IUnknown_QueryInterface(object, &IID_IMFByteStream, (void **)&stream);
1111 if (!source && !stream)
1113 WARN("Unsupported object type.\n");
1114 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
1115 return E_UNEXPECTED;
1118 if (sync)
1120 if (stream)
1121 hr = IMFSourceResolver_CreateObjectFromByteStream(player->resolver, stream, NULL,
1122 MF_RESOLUTION_MEDIASOURCE, player->propstore, &obj_type, &object);
1123 else
1124 IUnknown_AddRef(object);
1126 if (SUCCEEDED(hr))
1127 hr = media_item_set_source(item, object);
1129 IUnknown_Release(object);
1131 if (SUCCEEDED(hr))
1133 *ret = &item->IMFPMediaItem_iface;
1134 IMFPMediaItem_AddRef(*ret);
1137 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
1139 else
1141 if (stream)
1143 hr = IMFSourceResolver_BeginCreateObjectFromByteStream(player->resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE,
1144 player->propstore, NULL, &player->resolver_callback, (IUnknown *)&item->IMFPMediaItem_iface);
1146 else
1148 /* Resolver callback will check again if item's object is a source. */
1149 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, &player->resolver_callback,
1150 (IUnknown *)&item->IMFPMediaItem_iface);
1153 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
1156 if (source)
1157 IMFMediaSource_Release(source);
1158 if (stream)
1159 IMFByteStream_Release(stream);
1161 return hr;
1164 static HRESULT WINAPI media_player_CreateMediaItemFromObject(IMFPMediaPlayer *iface,
1165 IUnknown *object, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **item)
1167 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1168 HRESULT hr;
1170 TRACE("%p, %p, %d, %lx, %p.\n", iface, object, sync, user_data, item);
1172 EnterCriticalSection(&player->cs);
1173 if (player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
1174 hr = MF_E_SHUTDOWN;
1175 else
1176 hr = media_player_create_item_from_object(player, object, sync, user_data, item);
1177 LeaveCriticalSection(&player->cs);
1179 return hr;
1182 static HRESULT media_item_create_source_node(struct media_item *item, IMFStreamDescriptor *sd,
1183 IMFTopologyNode **node)
1185 HRESULT hr;
1187 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, node)))
1189 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_SOURCE, (IUnknown *)item->source);
1190 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)item->pd);
1191 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd);
1192 if (item->start_position)
1193 IMFTopologyNode_SetUINT64(*node, &MF_TOPONODE_MEDIASTART, item->start_position);
1194 if (item->stop_position)
1195 IMFTopologyNode_SetUINT64(*node, &MF_TOPONODE_MEDIASTOP, item->stop_position);
1198 return hr;
1201 static HRESULT media_item_create_sink_node(IUnknown *sink, IMFTopologyNode **node)
1203 HRESULT hr;
1205 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, node)))
1206 IMFTopologyNode_SetObject(*node, sink);
1208 return hr;
1211 static HRESULT media_item_create_topology(struct media_player *player, struct media_item *item, IMFTopology **out)
1213 IMFTopologyNode *src_node, *sink_node;
1214 BOOL selected, video_added = FALSE;
1215 IMFStreamDescriptor *sd;
1216 IMFTopology *topology;
1217 unsigned int idx;
1218 IUnknown *sink;
1219 HRESULT hr;
1220 GUID major;
1222 if (FAILED(hr = MFCreateTopology(&topology)))
1223 return hr;
1225 /* Set up branches for all selected streams. */
1227 idx = 0;
1228 while (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, idx++, &selected, &sd)))
1230 if (!selected || FAILED(media_item_get_stream_type(sd, &major)))
1232 IMFStreamDescriptor_Release(sd);
1233 continue;
1236 sink = NULL;
1238 if (SUCCEEDED(IMFStreamDescriptor_GetUnknown(sd, &_MF_CUSTOM_SINK, &IID_IUnknown, (void **)&sink)))
1240 /* User sink is attached as-is. */
1242 else if (IsEqualGUID(&major, &MFMediaType_Audio))
1244 if (FAILED(hr = MFCreateAudioRendererActivate((IMFActivate **)&sink)))
1245 WARN("Failed to create SAR activation object, hr %#x.\n", hr);
1247 else if (IsEqualGUID(&major, &MFMediaType_Video) && player->output_window && !video_added)
1249 if (FAILED(hr = MFCreateVideoRendererActivate(player->output_window, (IMFActivate **)&sink)))
1250 WARN("Failed to create EVR activation object, hr %#x.\n", hr);
1251 video_added = SUCCEEDED(hr);
1254 if (sink)
1256 hr = media_item_create_source_node(item, sd, &src_node);
1257 if (SUCCEEDED(hr))
1258 hr = media_item_create_sink_node(sink, &sink_node);
1260 if (SUCCEEDED(hr))
1262 IMFTopology_AddNode(topology, src_node);
1263 IMFTopology_AddNode(topology, sink_node);
1264 IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0);
1267 if (src_node)
1268 IMFTopologyNode_Release(src_node);
1269 if (sink_node)
1270 IMFTopologyNode_Release(sink_node);
1272 IUnknown_Release(sink);
1275 IMFStreamDescriptor_Release(sd);
1278 IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, TRUE);
1280 *out = topology;
1282 return S_OK;
1285 static HRESULT WINAPI media_player_SetMediaItem(IMFPMediaPlayer *iface, IMFPMediaItem *item_iface)
1287 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1288 struct media_item *item;
1289 IMFTopology *topology;
1290 HRESULT hr;
1292 TRACE("%p, %p.\n", iface, item_iface);
1294 if (!item_iface)
1295 return E_POINTER;
1297 item = unsafe_impl_from_IMFPMediaItem(item_iface);
1298 if (item->player != iface)
1299 return E_INVALIDARG;
1301 if (FAILED(hr = media_item_create_topology(player, item, &topology)))
1302 return hr;
1304 IMFTopology_SetUnknown(topology, &_MF_TOPO_MEDIA_ITEM, (IUnknown *)item_iface);
1305 hr = IMFMediaSession_SetTopology(player->session, MFSESSION_SETTOPOLOGY_IMMEDIATE, topology);
1306 IMFTopology_Release(topology);
1308 return hr;
1311 static HRESULT WINAPI media_player_ClearMediaItem(IMFPMediaPlayer *iface)
1313 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1315 TRACE("%p.\n", iface);
1317 return IMFMediaSession_SetTopology(player->session, MFSESSION_SETTOPOLOGY_CLEAR_CURRENT, NULL);
1320 static HRESULT WINAPI media_player_GetMediaItem(IMFPMediaPlayer *iface, IMFPMediaItem **item)
1322 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1323 HRESULT hr = S_OK;
1325 TRACE("%p, %p.\n", iface, item);
1327 if (!item)
1328 return E_POINTER;
1330 EnterCriticalSection(&player->cs);
1331 if (player->state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
1332 hr = MF_E_SHUTDOWN;
1333 else if (!player->item)
1334 hr = MF_E_NOT_FOUND;
1335 else
1337 *item = player->item;
1338 IMFPMediaItem_AddRef(player->item);
1340 LeaveCriticalSection(&player->cs);
1342 return hr;
1345 static HRESULT WINAPI media_player_GetVolume(IMFPMediaPlayer *iface, float *volume)
1347 FIXME("%p, %p.\n", iface, volume);
1349 return E_NOTIMPL;
1352 static HRESULT WINAPI media_player_SetVolume(IMFPMediaPlayer *iface, float volume)
1354 FIXME("%p, %.8e.\n", iface, volume);
1356 return E_NOTIMPL;
1359 static HRESULT WINAPI media_player_GetBalance(IMFPMediaPlayer *iface, float *balance)
1361 FIXME("%p, %p.\n", iface, balance);
1363 return E_NOTIMPL;
1366 static HRESULT WINAPI media_player_SetBalance(IMFPMediaPlayer *iface, float balance)
1368 FIXME("%p, %.8e.\n", iface, balance);
1370 return E_NOTIMPL;
1373 static HRESULT WINAPI media_player_GetMute(IMFPMediaPlayer *iface, BOOL *mute)
1375 FIXME("%p, %p.\n", iface, mute);
1377 return E_NOTIMPL;
1380 static HRESULT WINAPI media_player_SetMute(IMFPMediaPlayer *iface, BOOL mute)
1382 FIXME("%p, %d.\n", iface, mute);
1384 return E_NOTIMPL;
1387 static HRESULT media_player_get_display_control(const struct media_player *player,
1388 IMFVideoDisplayControl **display_control)
1390 HRESULT hr = MFGetService((IUnknown *)player->session, &MR_VIDEO_RENDER_SERVICE,
1391 &IID_IMFVideoDisplayControl, (void **)display_control);
1392 if (SUCCEEDED(hr)) return hr;
1393 return hr == MF_E_SHUTDOWN ? hr : MF_E_INVALIDREQUEST;
1396 static HRESULT WINAPI media_player_GetNativeVideoSize(IMFPMediaPlayer *iface,
1397 SIZE *video, SIZE *arvideo)
1399 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1400 IMFVideoDisplayControl *display_control;
1401 HRESULT hr;
1403 TRACE("%p, %p, %p.\n", iface, video, arvideo);
1405 if (SUCCEEDED(hr = media_player_get_display_control(player, &display_control)))
1407 hr = IMFVideoDisplayControl_GetNativeVideoSize(display_control, video, arvideo);
1408 IMFVideoDisplayControl_Release(display_control);
1411 return hr;
1414 static HRESULT WINAPI media_player_GetIdealVideoSize(IMFPMediaPlayer *iface,
1415 SIZE *min_size, SIZE *max_size)
1417 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1418 IMFVideoDisplayControl *display_control;
1419 HRESULT hr;
1421 TRACE("%p, %p, %p.\n", iface, min_size, max_size);
1423 if (SUCCEEDED(hr = media_player_get_display_control(player, &display_control)))
1425 hr = IMFVideoDisplayControl_GetIdealVideoSize(display_control, min_size, max_size);
1426 IMFVideoDisplayControl_Release(display_control);
1429 return hr;
1432 static HRESULT WINAPI media_player_SetVideoSourceRect(IMFPMediaPlayer *iface,
1433 MFVideoNormalizedRect const *rect)
1435 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1436 IMFVideoDisplayControl *display_control;
1437 RECT dst_rect;
1438 HRESULT hr;
1440 TRACE("%p, %p.\n", iface, rect);
1442 if (!GetClientRect(player->output_window, &dst_rect))
1443 hr = HRESULT_FROM_WIN32(GetLastError());
1444 else if (SUCCEEDED(hr = media_player_get_display_control(player, &display_control)))
1446 hr = IMFVideoDisplayControl_SetVideoPosition(display_control, rect, &dst_rect);
1447 IMFVideoDisplayControl_Release(display_control);
1450 return hr;
1453 static HRESULT WINAPI media_player_GetVideoSourceRect(IMFPMediaPlayer *iface,
1454 MFVideoNormalizedRect *rect)
1456 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1457 IMFVideoDisplayControl *display_control;
1458 HRESULT hr;
1459 RECT dest;
1461 TRACE("%p, %p.\n", iface, rect);
1463 if (SUCCEEDED(hr = media_player_get_display_control(player, &display_control)))
1465 hr = IMFVideoDisplayControl_GetVideoPosition(display_control, rect, &dest);
1466 IMFVideoDisplayControl_Release(display_control);
1469 return hr;
1472 static HRESULT WINAPI media_player_SetAspectRatioMode(IMFPMediaPlayer *iface, DWORD mode)
1474 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1475 IMFVideoDisplayControl *display_control;
1476 HRESULT hr;
1478 TRACE("%p, %u.\n", iface, mode);
1480 if (SUCCEEDED(hr = media_player_get_display_control(player, &display_control)))
1482 hr = IMFVideoDisplayControl_SetAspectRatioMode(display_control, mode);
1483 IMFVideoDisplayControl_Release(display_control);
1486 return hr;
1489 static HRESULT WINAPI media_player_GetAspectRatioMode(IMFPMediaPlayer *iface,
1490 DWORD *mode)
1492 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1493 IMFVideoDisplayControl *display_control;
1494 HRESULT hr;
1496 TRACE("%p, %p.\n", iface, mode);
1498 if (SUCCEEDED(hr = media_player_get_display_control(player, &display_control)))
1500 hr = IMFVideoDisplayControl_GetAspectRatioMode(display_control, mode);
1501 IMFVideoDisplayControl_Release(display_control);
1504 return hr;
1507 static HRESULT WINAPI media_player_GetVideoWindow(IMFPMediaPlayer *iface, HWND *window)
1509 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1511 TRACE("%p, %p.\n", iface, window);
1513 *window = player->output_window;
1515 return S_OK;
1518 static HRESULT WINAPI media_player_UpdateVideo(IMFPMediaPlayer *iface)
1520 FIXME("%p.\n", iface);
1522 return E_NOTIMPL;
1525 static HRESULT WINAPI media_player_SetBorderColor(IMFPMediaPlayer *iface, COLORREF color)
1527 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1528 IMFVideoDisplayControl *display_control;
1529 HRESULT hr;
1531 TRACE("%p, %#x.\n", iface, color);
1533 if (SUCCEEDED(hr = media_player_get_display_control(player, &display_control)))
1535 hr = IMFVideoDisplayControl_SetBorderColor(display_control, color);
1536 IMFVideoDisplayControl_Release(display_control);
1539 return hr;
1542 static HRESULT WINAPI media_player_GetBorderColor(IMFPMediaPlayer *iface, COLORREF *color)
1544 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1545 IMFVideoDisplayControl *display_control;
1546 HRESULT hr;
1548 TRACE("%p, %p.\n", iface, color);
1550 if (SUCCEEDED(hr = media_player_get_display_control(player, &display_control)))
1552 hr = IMFVideoDisplayControl_GetBorderColor(display_control, color);
1553 IMFVideoDisplayControl_Release(display_control);
1556 return hr;
1559 static HRESULT WINAPI media_player_InsertEffect(IMFPMediaPlayer *iface, IUnknown *effect,
1560 BOOL optional)
1562 FIXME("%p, %p, %d.\n", iface, effect, optional);
1564 return E_NOTIMPL;
1567 static HRESULT WINAPI media_player_RemoveEffect(IMFPMediaPlayer *iface, IUnknown *effect)
1569 FIXME("%p, %p.\n", iface, effect);
1571 return E_NOTIMPL;
1574 static HRESULT WINAPI media_player_RemoveAllEffects(IMFPMediaPlayer *iface)
1576 FIXME("%p.\n", iface);
1578 return E_NOTIMPL;
1581 static HRESULT WINAPI media_player_Shutdown(IMFPMediaPlayer *iface)
1583 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
1585 TRACE("%p.\n", iface);
1587 EnterCriticalSection(&player->cs);
1588 media_player_set_state(player, MFP_MEDIAPLAYER_STATE_SHUTDOWN);
1589 if (player->item)
1591 IMFPMediaItem_Release(player->item);
1592 player->item = NULL;
1594 LeaveCriticalSection(&player->cs);
1596 return S_OK;
1599 static const IMFPMediaPlayerVtbl media_player_vtbl =
1601 media_player_QueryInterface,
1602 media_player_AddRef,
1603 media_player_Release,
1604 media_player_Play,
1605 media_player_Pause,
1606 media_player_Stop,
1607 media_player_FrameStep,
1608 media_player_SetPosition,
1609 media_player_GetPosition,
1610 media_player_GetDuration,
1611 media_player_SetRate,
1612 media_player_GetRate,
1613 media_player_GetSupportedRates,
1614 media_player_GetState,
1615 media_player_CreateMediaItemFromURL,
1616 media_player_CreateMediaItemFromObject,
1617 media_player_SetMediaItem,
1618 media_player_ClearMediaItem,
1619 media_player_GetMediaItem,
1620 media_player_GetVolume,
1621 media_player_SetVolume,
1622 media_player_GetBalance,
1623 media_player_SetBalance,
1624 media_player_GetMute,
1625 media_player_SetMute,
1626 media_player_GetNativeVideoSize,
1627 media_player_GetIdealVideoSize,
1628 media_player_SetVideoSourceRect,
1629 media_player_GetVideoSourceRect,
1630 media_player_SetAspectRatioMode,
1631 media_player_GetAspectRatioMode,
1632 media_player_GetVideoWindow,
1633 media_player_UpdateVideo,
1634 media_player_SetBorderColor,
1635 media_player_GetBorderColor,
1636 media_player_InsertEffect,
1637 media_player_RemoveEffect,
1638 media_player_RemoveAllEffects,
1639 media_player_Shutdown,
1642 static HRESULT WINAPI media_player_propstore_QueryInterface(IPropertyStore *iface,
1643 REFIID riid, void **obj)
1645 struct media_player *player = impl_from_IPropertyStore(iface);
1646 return IMFPMediaPlayer_QueryInterface(&player->IMFPMediaPlayer_iface, riid, obj);
1649 static ULONG WINAPI media_player_propstore_AddRef(IPropertyStore *iface)
1651 struct media_player *player = impl_from_IPropertyStore(iface);
1652 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1655 static ULONG WINAPI media_player_propstore_Release(IPropertyStore *iface)
1657 struct media_player *player = impl_from_IPropertyStore(iface);
1658 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1661 static HRESULT WINAPI media_player_propstore_GetCount(IPropertyStore *iface, DWORD *count)
1663 struct media_player *player = impl_from_IPropertyStore(iface);
1665 TRACE("%p, %p.\n", iface, count);
1667 return IPropertyStore_GetCount(player->propstore, count);
1670 static HRESULT WINAPI media_player_propstore_GetAt(IPropertyStore *iface, DWORD prop, PROPERTYKEY *key)
1672 struct media_player *player = impl_from_IPropertyStore(iface);
1674 TRACE("%p, %u, %p.\n", iface, prop, key);
1676 return IPropertyStore_GetAt(player->propstore, prop, key);
1679 static HRESULT WINAPI media_player_propstore_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *value)
1681 struct media_player *player = impl_from_IPropertyStore(iface);
1683 TRACE("%p, %p, %p.\n", iface, key, value);
1685 return IPropertyStore_GetValue(player->propstore, key, value);
1688 static HRESULT WINAPI media_player_propstore_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT value)
1690 struct media_player *player = impl_from_IPropertyStore(iface);
1692 TRACE("%p, %p, %p.\n", iface, key, value);
1694 return IPropertyStore_SetValue(player->propstore, key, value);
1697 static HRESULT WINAPI media_player_propstore_Commit(IPropertyStore *iface)
1699 struct media_player *player = impl_from_IPropertyStore(iface);
1701 TRACE("%p.\n", iface);
1703 return IPropertyStore_Commit(player->propstore);
1706 static const IPropertyStoreVtbl media_player_propstore_vtbl =
1708 media_player_propstore_QueryInterface,
1709 media_player_propstore_AddRef,
1710 media_player_propstore_Release,
1711 media_player_propstore_GetCount,
1712 media_player_propstore_GetAt,
1713 media_player_propstore_GetValue,
1714 media_player_propstore_SetValue,
1715 media_player_propstore_Commit,
1718 static HRESULT WINAPI media_player_callback_QueryInterface(IMFAsyncCallback *iface,
1719 REFIID riid, void **obj)
1721 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
1722 IsEqualIID(riid, &IID_IUnknown))
1724 *obj = iface;
1725 IMFAsyncCallback_AddRef(iface);
1726 return S_OK;
1729 *obj = NULL;
1730 return E_NOINTERFACE;
1733 static ULONG WINAPI media_player_resolver_callback_AddRef(IMFAsyncCallback *iface)
1735 struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
1736 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1739 static ULONG WINAPI media_player_resolver_callback_Release(IMFAsyncCallback *iface)
1741 struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
1742 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1745 static HRESULT WINAPI media_player_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags,
1746 DWORD *queue)
1748 return E_NOTIMPL;
1751 static HRESULT WINAPI media_player_resolver_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1753 struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
1754 struct media_event *event;
1755 IUnknown *object, *state;
1756 MF_OBJECT_TYPE obj_type;
1757 struct media_item *item;
1758 HRESULT hr;
1760 if (FAILED(IMFAsyncResult_GetState(result, &state)))
1761 return S_OK;
1763 item = impl_from_IMFPMediaItem((IMFPMediaItem *)state);
1765 if (item->object)
1767 if (FAILED(hr = IUnknown_QueryInterface(item->object, &IID_IMFMediaSource, (void **)&object)))
1768 hr = IMFSourceResolver_EndCreateObjectFromByteStream(player->resolver, result, &obj_type, &object);
1770 else
1771 hr = IMFSourceResolver_EndCreateObjectFromURL(player->resolver, result, &obj_type, &object);
1773 if (SUCCEEDED(hr))
1775 hr = media_item_set_source(item, object);
1776 IUnknown_Release(object);
1779 if (FAILED(hr))
1780 WARN("Failed to set media source, hr %#x.\n", hr);
1782 if (FAILED(media_event_create(player, MFP_EVENT_TYPE_MEDIAITEM_CREATED, hr,
1783 &item->IMFPMediaItem_iface, &event)))
1785 WARN("Failed to create event object.\n");
1786 IUnknown_Release(state);
1787 return S_OK;
1789 event->u.item_created.dwUserData = item->user_data;
1791 media_player_queue_event(player, event);
1793 IUnknown_Release(&event->IUnknown_iface);
1794 IUnknown_Release(state);
1796 return S_OK;
1799 static const IMFAsyncCallbackVtbl media_player_resolver_callback_vtbl =
1801 media_player_callback_QueryInterface,
1802 media_player_resolver_callback_AddRef,
1803 media_player_resolver_callback_Release,
1804 media_player_callback_GetParameters,
1805 media_player_resolver_callback_Invoke,
1808 static ULONG WINAPI media_player_events_callback_AddRef(IMFAsyncCallback *iface)
1810 struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
1811 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1814 static ULONG WINAPI media_player_events_callback_Release(IMFAsyncCallback *iface)
1816 struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
1817 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1820 static HRESULT WINAPI media_player_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1822 struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
1823 struct media_event *event;
1824 IUnknown *state;
1826 if (FAILED(IMFAsyncResult_GetState(result, &state)))
1827 return S_OK;
1829 event = impl_event_from_IUnknown(state);
1831 if (player->callback)
1832 IMFPMediaPlayerCallback_OnMediaPlayerEvent(player->callback, &event->u.header);
1834 IUnknown_Release(state);
1836 return S_OK;
1839 static const IMFAsyncCallbackVtbl media_player_events_callback_vtbl =
1841 media_player_callback_QueryInterface,
1842 media_player_events_callback_AddRef,
1843 media_player_events_callback_Release,
1844 media_player_callback_GetParameters,
1845 media_player_events_callback_Invoke,
1848 static ULONG WINAPI media_player_session_events_callback_AddRef(IMFAsyncCallback *iface)
1850 struct media_player *player = impl_from_session_events_IMFAsyncCallback(iface);
1851 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1854 static ULONG WINAPI media_player_session_events_callback_Release(IMFAsyncCallback *iface)
1856 struct media_player *player = impl_from_session_events_IMFAsyncCallback(iface);
1857 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1860 static void media_player_change_state(struct media_player *player, MFP_MEDIAPLAYER_STATE state,
1861 HRESULT event_status, struct media_event **event)
1863 MFP_EVENT_TYPE event_type;
1865 EnterCriticalSection(&player->cs);
1867 if (state == MFP_MEDIAPLAYER_STATE_PLAYING)
1868 event_type = MFP_EVENT_TYPE_PLAY;
1869 else if (state == MFP_MEDIAPLAYER_STATE_PAUSED)
1870 event_type = MFP_EVENT_TYPE_PAUSE;
1871 else
1872 event_type = MFP_EVENT_TYPE_STOP;
1874 media_player_set_state(player, state);
1875 media_event_create(player, event_type, event_status, player->item, event);
1877 LeaveCriticalSection(&player->cs);
1880 static void media_player_set_item(struct media_player *player, IMFTopology *topology, HRESULT event_status,
1881 struct media_event **event)
1883 IMFPMediaItem *item;
1885 if (FAILED(IMFTopology_GetUnknown(topology, &_MF_TOPO_MEDIA_ITEM, &IID_IMFPMediaItem, (void **)&item)))
1886 return;
1888 EnterCriticalSection(&player->cs);
1890 if (player->item)
1891 IMFPMediaItem_Release(player->item);
1892 player->item = item;
1893 IMFPMediaItem_AddRef(player->item);
1895 media_event_create(player, MFP_EVENT_TYPE_MEDIAITEM_SET, event_status, item, event);
1897 LeaveCriticalSection(&player->cs);
1899 IMFPMediaItem_Release(item);
1902 static void media_player_clear_item(struct media_player *player, HRESULT event_status,
1903 struct media_event **event)
1905 IMFPMediaItem *item;
1907 EnterCriticalSection(&player->cs);
1909 item = player->item;
1910 player->item = NULL;
1912 media_event_create(player, MFP_EVENT_TYPE_MEDIAITEM_SET, event_status, item, event);
1914 LeaveCriticalSection(&player->cs);
1917 static void media_player_create_forward_event(struct media_player *player, HRESULT event_status, IMFMediaEvent *session_event,
1918 struct media_event **event)
1920 EnterCriticalSection(&player->cs);
1922 if (SUCCEEDED(media_event_create(player, MFP_EVENT_TYPE_MF, event_status, player->item, event)))
1924 IMFMediaEvent_GetType(session_event, &(*event)->u.event.MFEventType);
1925 (*event)->u.event.pMFMediaEvent = session_event;
1926 IMFMediaEvent_AddRef((*event)->u.event.pMFMediaEvent);
1929 LeaveCriticalSection(&player->cs);
1932 static HRESULT WINAPI media_player_session_events_callback_Invoke(IMFAsyncCallback *iface,
1933 IMFAsyncResult *result)
1935 struct media_player *player = impl_from_session_events_IMFAsyncCallback(iface);
1936 MediaEventType session_event_type = MEUnknown;
1937 struct media_event *event = NULL;
1938 IMFMediaEvent *session_event;
1939 MFP_MEDIAPLAYER_STATE state;
1940 HRESULT hr, event_status;
1941 IMFTopology *topology;
1942 unsigned int status;
1943 PROPVARIANT value;
1945 if (FAILED(hr = IMFMediaSession_EndGetEvent(player->session, result, &session_event)))
1946 return S_OK;
1948 IMFMediaEvent_GetType(session_event, &session_event_type);
1949 IMFMediaEvent_GetStatus(session_event, &event_status);
1951 switch (session_event_type)
1953 case MESessionStarted:
1954 case MESessionStopped:
1955 case MESessionPaused:
1957 if (session_event_type == MESessionStarted)
1958 state = MFP_MEDIAPLAYER_STATE_PLAYING;
1959 else if (session_event_type == MESessionPaused)
1960 state = MFP_MEDIAPLAYER_STATE_PAUSED;
1961 else
1962 state = MFP_MEDIAPLAYER_STATE_STOPPED;
1964 media_player_change_state(player, state, event_status, &event);
1966 break;
1968 case MESessionTopologySet:
1970 value.vt = VT_EMPTY;
1971 if (SUCCEEDED(IMFMediaEvent_GetValue(session_event, &value)))
1973 if (value.vt == VT_EMPTY)
1975 media_player_clear_item(player, event_status, &event);
1977 else if (value.vt == VT_UNKNOWN && value.punkVal &&
1978 SUCCEEDED(IUnknown_QueryInterface(value.punkVal, &IID_IMFTopology, (void **)&topology)))
1980 media_player_set_item(player, topology, event_status, &event);
1981 IMFTopology_Release(topology);
1983 PropVariantClear(&value);
1986 break;
1988 case MESessionTopologyStatus:
1990 if (SUCCEEDED(IMFMediaEvent_GetUINT32(session_event, &MF_EVENT_TOPOLOGY_STATUS, &status)) &&
1991 status == MF_TOPOSTATUS_ENDED)
1993 media_event_create(player, MFP_EVENT_TYPE_PLAYBACK_ENDED, event_status, player->item, &event);
1996 break;
1998 case MEBufferingStarted:
1999 case MEBufferingStopped:
2000 case MEExtendedType:
2001 case MEReconnectStart:
2002 case MEReconnectEnd:
2003 case MERendererEvent:
2004 case MEStreamSinkFormatChanged:
2006 media_player_create_forward_event(player, event_status, session_event, &event);
2008 break;
2010 case MEError:
2012 media_event_create(player, MFP_EVENT_TYPE_ERROR, event_status, NULL, &event);
2014 break;
2016 default:
2020 if (event)
2022 media_player_queue_event(player, event);
2023 IUnknown_Release(&event->IUnknown_iface);
2026 IMFMediaSession_BeginGetEvent(player->session, &player->session_events_callback, NULL);
2027 IMFMediaEvent_Release(session_event);
2029 return S_OK;
2032 static const IMFAsyncCallbackVtbl media_player_session_events_callback_vtbl =
2034 media_player_callback_QueryInterface,
2035 media_player_session_events_callback_AddRef,
2036 media_player_session_events_callback_Release,
2037 media_player_callback_GetParameters,
2038 media_player_session_events_callback_Invoke,
2041 /***********************************************************************
2042 * MFPCreateMediaPlayer (mfplay.@)
2044 HRESULT WINAPI MFPCreateMediaPlayer(const WCHAR *url, BOOL start_playback, MFP_CREATION_OPTIONS options,
2045 IMFPMediaPlayerCallback *callback, HWND window, IMFPMediaPlayer **player)
2047 struct media_player *object;
2048 IMFPMediaItem *item;
2049 HRESULT hr;
2051 TRACE("%s, %d, %#x, %p, %p, %p.\n", debugstr_w(url), start_playback, options, callback, window, player);
2053 if (!player)
2054 return E_POINTER;
2056 *player = NULL;
2058 if (!url && start_playback)
2059 return E_INVALIDARG;
2061 if (!(object = calloc(1, sizeof(*object))))
2062 return E_OUTOFMEMORY;
2064 platform_startup();
2066 object->IMFPMediaPlayer_iface.lpVtbl = &media_player_vtbl;
2067 object->IPropertyStore_iface.lpVtbl = &media_player_propstore_vtbl;
2068 object->resolver_callback.lpVtbl = &media_player_resolver_callback_vtbl;
2069 object->events_callback.lpVtbl = &media_player_events_callback_vtbl;
2070 object->session_events_callback.lpVtbl = &media_player_session_events_callback_vtbl;
2071 object->refcount = 1;
2072 object->callback = callback;
2073 if (object->callback)
2074 IMFPMediaPlayerCallback_AddRef(object->callback);
2075 object->options = options;
2076 object->output_window = window;
2077 InitializeCriticalSection(&object->cs);
2078 if (FAILED(hr = CreatePropertyStore(&object->propstore)))
2079 goto failed;
2080 if (FAILED(hr = MFCreateSourceResolver(&object->resolver)))
2081 goto failed;
2082 if (FAILED(hr = MFCreateMediaSession(NULL, &object->session)))
2083 goto failed;
2084 if (FAILED(hr = IMFMediaSession_BeginGetEvent(object->session, &object->session_events_callback, NULL)))
2085 goto failed;
2086 if (!(object->options & MFP_OPTION_FREE_THREADED_CALLBACK))
2088 object->event_window = CreateWindowW(eventclassW, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE,
2089 0, mfplay_instance, NULL);
2092 if (url)
2094 if (FAILED(hr = media_player_create_item_from_url(object, url, TRUE, 0, &item)))
2096 WARN("Failed to create media item, hr %#x.\n", hr);
2097 goto failed;
2100 hr = IMFPMediaPlayer_SetMediaItem(&object->IMFPMediaPlayer_iface, item);
2101 IMFPMediaItem_Release(item);
2102 if (FAILED(hr))
2104 WARN("Failed to set media item, hr %#x.\n", hr);
2105 goto failed;
2108 if (start_playback)
2109 IMFPMediaPlayer_Play(&object->IMFPMediaPlayer_iface);
2112 *player = &object->IMFPMediaPlayer_iface;
2114 return S_OK;
2116 failed:
2118 IMFPMediaPlayer_Release(&object->IMFPMediaPlayer_iface);
2120 return hr;
2123 static void media_player_register_window_class(void)
2125 WNDCLASSW cls = { 0 };
2127 cls.lpfnWndProc = media_player_event_proc;
2128 cls.hInstance = mfplay_instance;
2129 cls.lpszClassName = eventclassW;
2131 RegisterClassW(&cls);
2134 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
2136 switch (reason)
2138 case DLL_PROCESS_ATTACH:
2139 mfplay_instance = instance;
2140 DisableThreadLibraryCalls(instance);
2141 media_player_register_window_class();
2142 break;
2143 case DLL_PROCESS_DETACH:
2144 if (reserved) break;
2145 UnregisterClassW(eventclassW, instance);
2146 break;
2149 return TRUE;