mfplay: Implement GetMetadata().
[wine.git] / dlls / mfplay / player.c
blob9f20d6c1a2adb55fceeae11a8f4705b7867b6c3e
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>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "mfapi.h"
26 #include "mfplay.h"
28 #include "wine/debug.h"
29 #include "wine/heap.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
33 static const WCHAR eventclassW[] = L"MediaPlayerEventCallbackClass";
35 static LONG startup_refcount;
36 static HINSTANCE mfplay_instance;
38 static void platform_startup(void)
40 if (InterlockedIncrement(&startup_refcount) == 1)
41 MFStartup(MF_VERSION, MFSTARTUP_FULL);
44 static void platform_shutdown(void)
46 if (InterlockedDecrement(&startup_refcount) == 0)
47 MFShutdown();
50 struct media_item
52 IMFPMediaItem IMFPMediaItem_iface;
53 LONG refcount;
54 IMFPMediaPlayer *player;
55 IMFMediaSource *source;
56 IMFPresentationDescriptor *pd;
57 DWORD_PTR user_data;
60 struct media_player
62 IMFPMediaPlayer IMFPMediaPlayer_iface;
63 IPropertyStore IPropertyStore_iface;
64 IMFAsyncCallback resolver_callback;
65 IMFAsyncCallback events_callback;
66 IMFAsyncCallback session_events_callback;
67 LONG refcount;
68 IMFPMediaPlayerCallback *callback;
69 IPropertyStore *propstore;
70 IMFSourceResolver *resolver;
71 IMFMediaSession *session;
72 MFP_CREATION_OPTIONS options;
73 MFP_MEDIAPLAYER_STATE state;
74 HWND event_window;
75 HWND output_window;
76 CRITICAL_SECTION cs;
79 struct generic_event
81 MFP_EVENT_HEADER header;
82 IMFPMediaItem *item;
85 struct media_event
87 IUnknown IUnknown_iface;
88 LONG refcount;
89 union
91 MFP_EVENT_HEADER header;
92 struct generic_event generic;
93 MFP_PLAY_EVENT play;
94 MFP_PAUSE_EVENT pause;
95 MFP_STOP_EVENT stop;
96 MFP_POSITION_SET_EVENT position_set;
97 MFP_RATE_SET_EVENT rate_set;
98 MFP_MEDIAITEM_CREATED_EVENT item_created;
99 MFP_MEDIAITEM_SET_EVENT item_set;
100 MFP_MEDIAITEM_CLEARED_EVENT item_cleared;
101 MFP_MF_EVENT event;
102 MFP_ERROR_EVENT error;
103 MFP_PLAYBACK_ENDED_EVENT ended;
104 MFP_ACQUIRE_USER_CREDENTIAL_EVENT acquire_creds;
105 } u;
108 static struct media_player *impl_from_IMFPMediaPlayer(IMFPMediaPlayer *iface)
110 return CONTAINING_RECORD(iface, struct media_player, IMFPMediaPlayer_iface);
113 static struct media_player *impl_from_IPropertyStore(IPropertyStore *iface)
115 return CONTAINING_RECORD(iface, struct media_player, IPropertyStore_iface);
118 static struct media_player *impl_from_resolver_IMFAsyncCallback(IMFAsyncCallback *iface)
120 return CONTAINING_RECORD(iface, struct media_player, resolver_callback);
123 static struct media_player *impl_from_events_IMFAsyncCallback(IMFAsyncCallback *iface)
125 return CONTAINING_RECORD(iface, struct media_player, events_callback);
128 static struct media_player *impl_from_session_events_IMFAsyncCallback(IMFAsyncCallback *iface)
130 return CONTAINING_RECORD(iface, struct media_player, session_events_callback);
133 static struct media_item *impl_from_IMFPMediaItem(IMFPMediaItem *iface)
135 return CONTAINING_RECORD(iface, struct media_item, IMFPMediaItem_iface);
138 static struct media_event *impl_event_from_IUnknown(IUnknown *iface)
140 return CONTAINING_RECORD(iface, struct media_event, IUnknown_iface);
143 static HRESULT WINAPI media_event_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
145 if (IsEqualIID(riid, &IID_IUnknown))
147 *obj = iface;
148 IUnknown_AddRef(iface);
149 return S_OK;
152 *obj = NULL;
153 return E_NOINTERFACE;
156 static ULONG WINAPI media_event_AddRef(IUnknown *iface)
158 struct media_event *event = impl_event_from_IUnknown(iface);
159 ULONG refcount = InterlockedIncrement(&event->refcount);
161 TRACE("%p, refcount %u.\n", iface, refcount);
163 return refcount;
166 static ULONG WINAPI media_event_Release(IUnknown *iface)
168 struct media_event *event = impl_event_from_IUnknown(iface);
169 ULONG refcount = InterlockedDecrement(&event->refcount);
171 TRACE("%p, refcount %u.\n", iface, refcount);
173 if (!refcount)
175 if (event->u.header.pMediaPlayer)
176 IMFPMediaPlayer_Release(event->u.header.pMediaPlayer);
177 if (event->u.header.pPropertyStore)
178 IPropertyStore_Release(event->u.header.pPropertyStore);
180 switch (event->u.header.eEventType)
182 /* Most types share same layout. */
183 case MFP_EVENT_TYPE_PLAY:
184 case MFP_EVENT_TYPE_PAUSE:
185 case MFP_EVENT_TYPE_STOP:
186 case MFP_EVENT_TYPE_POSITION_SET:
187 case MFP_EVENT_TYPE_RATE_SET:
188 case MFP_EVENT_TYPE_MEDIAITEM_CREATED:
189 case MFP_EVENT_TYPE_MEDIAITEM_SET:
190 case MFP_EVENT_TYPE_FRAME_STEP:
191 case MFP_EVENT_TYPE_MEDIAITEM_CLEARED:
192 case MFP_EVENT_TYPE_PLAYBACK_ENDED:
193 if (event->u.generic.item)
194 IMFPMediaItem_Release(event->u.generic.item);
195 break;
196 case MFP_EVENT_TYPE_MF:
197 if (event->u.event.pMFMediaEvent)
198 IMFMediaEvent_Release(event->u.event.pMFMediaEvent);
199 if (event->u.event.pMediaItem)
200 IMFPMediaItem_Release(event->u.event.pMediaItem);
201 break;
202 default:
203 FIXME("Unsupported event %u.\n", event->u.header.eEventType);
204 break;
207 heap_free(event);
210 return refcount;
213 static const IUnknownVtbl media_event_vtbl =
215 media_event_QueryInterface,
216 media_event_AddRef,
217 media_event_Release,
220 static HRESULT media_event_create(struct media_player *player, MFP_EVENT_TYPE event_type,
221 HRESULT hr, struct media_event **event)
223 struct media_event *object;
225 if (!(object = heap_alloc_zero(sizeof(*object))))
226 return E_OUTOFMEMORY;
228 object->IUnknown_iface.lpVtbl = &media_event_vtbl;
229 object->refcount = 1;
230 object->u.header.eEventType = event_type;
231 object->u.header.hrEvent = hr;
232 object->u.header.pMediaPlayer = &player->IMFPMediaPlayer_iface;
233 IMFPMediaPlayer_AddRef(object->u.header.pMediaPlayer);
234 object->u.header.eState = player->state;
235 /* FIXME: set properties for some events? */
237 *event = object;
239 return S_OK;
242 static LRESULT WINAPI media_player_event_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
244 struct media_event *event = (void *)lparam;
245 struct media_player *player;
247 if (msg == WM_USER)
249 player = impl_from_IMFPMediaPlayer(event->u.header.pMediaPlayer);
250 if (player->callback)
251 IMFPMediaPlayerCallback_OnMediaPlayerEvent(player->callback, &event->u.header);
252 IUnknown_Release(&event->IUnknown_iface);
253 return 0;
256 return DefWindowProcW(hwnd, msg, wparam, lparam);
259 static void media_player_set_state(struct media_player *player, MFP_MEDIAPLAYER_STATE state)
261 if (player->state != MFP_MEDIAPLAYER_STATE_SHUTDOWN)
263 if (state == MFP_MEDIAPLAYER_STATE_SHUTDOWN)
264 IMFMediaSession_Shutdown(player->session);
265 player->state = state;
269 static HRESULT WINAPI media_item_QueryInterface(IMFPMediaItem *iface, REFIID riid, void **obj)
271 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
273 if (IsEqualIID(riid, &IID_IMFPMediaItem) ||
274 IsEqualIID(riid, &IID_IUnknown))
276 *obj = iface;
277 IMFPMediaItem_AddRef(iface);
278 return S_OK;
281 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
282 *obj = NULL;
283 return E_NOINTERFACE;
286 static ULONG WINAPI media_item_AddRef(IMFPMediaItem *iface)
288 struct media_item *item = impl_from_IMFPMediaItem(iface);
289 ULONG refcount = InterlockedIncrement(&item->refcount);
291 TRACE("%p, refcount %u.\n", iface, refcount);
293 return refcount;
296 static ULONG WINAPI media_item_Release(IMFPMediaItem *iface)
298 struct media_item *item = impl_from_IMFPMediaItem(iface);
299 ULONG refcount = InterlockedDecrement(&item->refcount);
301 TRACE("%p, refcount %u.\n", iface, refcount);
303 if (!refcount)
305 if (item->player)
306 IMFPMediaPlayer_Release(item->player);
307 if (item->source)
308 IMFMediaSource_Release(item->source);
309 if (item->pd)
310 IMFPresentationDescriptor_Release(item->pd);
311 heap_free(item);
314 return refcount;
317 static HRESULT WINAPI media_item_GetMediaPlayer(IMFPMediaItem *iface,
318 IMFPMediaPlayer **player)
320 struct media_item *item = impl_from_IMFPMediaItem(iface);
322 TRACE("%p, %p.\n", iface, player);
324 *player = item->player;
325 IMFPMediaPlayer_AddRef(*player);
327 return S_OK;
330 static HRESULT WINAPI media_item_GetURL(IMFPMediaItem *iface, LPWSTR *url)
332 FIXME("%p, %p.\n", iface, url);
334 return E_NOTIMPL;
337 static HRESULT WINAPI media_item_GetObject(IMFPMediaItem *iface, IUnknown **obj)
339 FIXME("%p, %p.\n", iface, obj);
341 return E_NOTIMPL;
344 static HRESULT WINAPI media_item_GetUserData(IMFPMediaItem *iface, DWORD_PTR *user_data)
346 struct media_item *item = impl_from_IMFPMediaItem(iface);
348 TRACE("%p, %p.\n", iface, user_data);
350 *user_data = item->user_data;
352 return S_OK;
355 static HRESULT WINAPI media_item_SetUserData(IMFPMediaItem *iface, DWORD_PTR user_data)
357 struct media_item *item = impl_from_IMFPMediaItem(iface);
359 TRACE("%p, %lx.\n", iface, user_data);
361 item->user_data = user_data;
363 return S_OK;
366 static HRESULT WINAPI media_item_GetStartStopPosition(IMFPMediaItem *iface, GUID *start_format,
367 PROPVARIANT *start_position, GUID *stop_format, PROPVARIANT *stop_position)
369 FIXME("%p, %p, %p, %p, %p.\n", iface, start_format, start_position, stop_format, stop_position);
371 return E_NOTIMPL;
374 static HRESULT WINAPI media_item_SetStartStopPosition(IMFPMediaItem *iface, const GUID *start_format,
375 const PROPVARIANT *start_position, const GUID *stop_format, const PROPVARIANT *stop_position)
377 FIXME("%p, %s, %p, %s, %p.\n", iface, debugstr_guid(start_format), start_position,
378 debugstr_guid(stop_format), stop_position);
380 return E_NOTIMPL;
383 static HRESULT WINAPI media_item_HasVideo(IMFPMediaItem *iface, BOOL *has_video, BOOL *selected)
385 FIXME("%p, %p, %p.\n", iface, has_video, selected);
387 return E_NOTIMPL;
390 static HRESULT WINAPI media_item_HasAudio(IMFPMediaItem *iface, BOOL *has_audio, BOOL *selected)
392 FIXME("%p, %p, %p.\n", iface, has_audio, selected);
394 return E_NOTIMPL;
397 static HRESULT WINAPI media_item_IsProtected(IMFPMediaItem *iface, BOOL *protected)
399 struct media_item *item = impl_from_IMFPMediaItem(iface);
401 TRACE("%p, %p.\n", iface, protected);
403 *protected = MFRequireProtectedEnvironment(item->pd) == S_OK;
405 return S_OK;
408 static HRESULT WINAPI media_item_GetDuration(IMFPMediaItem *iface, REFGUID format, PROPVARIANT *value)
410 struct media_item *item = impl_from_IMFPMediaItem(iface);
412 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), value);
414 return IMFPresentationDescriptor_GetItem(item->pd, &MF_PD_DURATION, value);
417 static HRESULT WINAPI media_item_GetNumberOfStreams(IMFPMediaItem *iface, DWORD *count)
419 struct media_item *item = impl_from_IMFPMediaItem(iface);
421 TRACE("%p, %p.\n", iface, count);
423 return IMFPresentationDescriptor_GetStreamDescriptorCount(item->pd, count);
426 static HRESULT WINAPI media_item_GetStreamSelection(IMFPMediaItem *iface, DWORD index, BOOL *selected)
428 struct media_item *item = impl_from_IMFPMediaItem(iface);
429 IMFStreamDescriptor *sd;
430 HRESULT hr;
432 TRACE("%p, %u, %p.\n", iface, index, selected);
434 if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, index, selected, &sd)))
435 IMFStreamDescriptor_Release(sd);
437 return hr;
440 static HRESULT WINAPI media_item_SetStreamSelection(IMFPMediaItem *iface, DWORD index, BOOL select)
442 struct media_item *item = impl_from_IMFPMediaItem(iface);
444 TRACE("%p, %u, %d.\n", iface, index, select);
446 return select ? IMFPresentationDescriptor_SelectStream(item->pd, index) :
447 IMFPresentationDescriptor_DeselectStream(item->pd, index);
450 static HRESULT WINAPI media_item_GetStreamAttribute(IMFPMediaItem *iface, DWORD index, REFGUID key,
451 PROPVARIANT *value)
453 struct media_item *item = impl_from_IMFPMediaItem(iface);
454 IMFStreamDescriptor *sd;
455 BOOL selected;
456 HRESULT hr;
458 TRACE("%p, %u, %s, %p.\n", iface, index, debugstr_guid(key), value);
460 if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(item->pd, index, &selected, &sd)))
462 hr = IMFStreamDescriptor_GetItem(sd, key, value);
463 IMFStreamDescriptor_Release(sd);
466 return hr;
469 static HRESULT WINAPI media_item_GetPresentationAttribute(IMFPMediaItem *iface, REFGUID key,
470 PROPVARIANT *value)
472 struct media_item *item = impl_from_IMFPMediaItem(iface);
474 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
476 return IMFPresentationDescriptor_GetItem(item->pd, key, value);
479 static HRESULT WINAPI media_item_GetCharacteristics(IMFPMediaItem *iface, MFP_MEDIAITEM_CHARACTERISTICS *flags)
481 struct media_item *item = impl_from_IMFPMediaItem(iface);
482 HRESULT hr;
484 TRACE("%p, %p.\n", iface, flags);
486 *flags = 0;
488 if (SUCCEEDED(hr = IMFMediaSource_GetCharacteristics(item->source, flags)))
490 *flags &= (MFP_MEDIAITEM_IS_LIVE | MFP_MEDIAITEM_CAN_SEEK |
491 MFP_MEDIAITEM_CAN_PAUSE | MFP_MEDIAITEM_HAS_SLOW_SEEK);
494 return hr;
497 static HRESULT WINAPI media_item_SetStreamSink(IMFPMediaItem *iface, DWORD index, IUnknown *sink)
499 FIXME("%p, %u, %p.\n", iface, index, sink);
501 return E_NOTIMPL;
504 static HRESULT WINAPI media_item_GetMetadata(IMFPMediaItem *iface, IPropertyStore **metadata)
506 struct media_item *item = impl_from_IMFPMediaItem(iface);
508 TRACE("%p, %p.\n", iface, metadata);
510 return MFGetService((IUnknown *)item->source, &MF_PROPERTY_HANDLER_SERVICE,
511 &IID_IPropertyStore, (void **)&metadata);
514 static const IMFPMediaItemVtbl media_item_vtbl =
516 media_item_QueryInterface,
517 media_item_AddRef,
518 media_item_Release,
519 media_item_GetMediaPlayer,
520 media_item_GetURL,
521 media_item_GetObject,
522 media_item_GetUserData,
523 media_item_SetUserData,
524 media_item_GetStartStopPosition,
525 media_item_SetStartStopPosition,
526 media_item_HasVideo,
527 media_item_HasAudio,
528 media_item_IsProtected,
529 media_item_GetDuration,
530 media_item_GetNumberOfStreams,
531 media_item_GetStreamSelection,
532 media_item_SetStreamSelection,
533 media_item_GetStreamAttribute,
534 media_item_GetPresentationAttribute,
535 media_item_GetCharacteristics,
536 media_item_SetStreamSink,
537 media_item_GetMetadata,
540 static HRESULT create_media_item(IMFPMediaPlayer *player, DWORD_PTR user_data, struct media_item **item)
542 struct media_item *object;
544 if (!(object = heap_alloc_zero(sizeof(*object))))
545 return E_OUTOFMEMORY;
547 object->IMFPMediaItem_iface.lpVtbl = &media_item_vtbl;
548 object->refcount = 1;
549 object->user_data = user_data;
550 object->player = player;
551 IMFPMediaPlayer_AddRef(object->player);
553 *item = object;
555 return S_OK;
558 static HRESULT media_item_set_source(struct media_item *item, IUnknown *object)
560 IMFPresentationDescriptor *pd;
561 IMFMediaSource *source;
562 HRESULT hr;
564 if (FAILED(hr = IUnknown_QueryInterface(object, &IID_IMFMediaSource, (void **)&source)))
565 return hr;
567 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd)))
569 WARN("Failed to get presentation descriptor, hr %#x.\n", hr);
570 IMFMediaSource_Release(source);
571 return hr;
574 item->source = source;
575 item->pd = pd;
577 return hr;
580 static void media_player_queue_event(struct media_player *player, struct media_event *event)
582 if (player->options & MFP_OPTION_FREE_THREADED_CALLBACK)
584 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, &player->events_callback, &event->IUnknown_iface);
586 else
588 IUnknown_AddRef(&event->IUnknown_iface);
589 PostMessageW(player->event_window, WM_USER, 0, (LPARAM)event);
593 static HRESULT WINAPI media_player_QueryInterface(IMFPMediaPlayer *iface, REFIID riid, void **obj)
595 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
597 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
599 if (IsEqualIID(riid, &IID_IMFPMediaPlayer) ||
600 IsEqualIID(riid, &IID_IUnknown))
602 *obj = &player->IMFPMediaPlayer_iface;
604 else if (IsEqualIID(riid, &IID_IPropertyStore))
606 *obj = &player->IPropertyStore_iface;
608 else
610 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
611 *obj = NULL;
613 return E_NOINTERFACE;
616 IUnknown_AddRef((IUnknown *)*obj);
617 return S_OK;
620 static ULONG WINAPI media_player_AddRef(IMFPMediaPlayer *iface)
622 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
623 ULONG refcount = InterlockedIncrement(&player->refcount);
625 TRACE("%p, refcount %u.\n", iface, refcount);
627 return refcount;
630 static ULONG WINAPI media_player_Release(IMFPMediaPlayer *iface)
632 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
633 ULONG refcount = InterlockedDecrement(&player->refcount);
635 TRACE("%p, refcount %u.\n", iface, refcount);
637 if (!refcount)
639 if (player->callback)
640 IMFPMediaPlayerCallback_Release(player->callback);
641 if (player->propstore)
642 IPropertyStore_Release(player->propstore);
643 if (player->resolver)
644 IMFSourceResolver_Release(player->resolver);
645 if (player->session)
646 IMFMediaSession_Release(player->session);
647 DestroyWindow(player->event_window);
648 DeleteCriticalSection(&player->cs);
649 heap_free(player);
651 platform_shutdown();
654 return refcount;
657 static HRESULT WINAPI media_player_Play(IMFPMediaPlayer *iface)
659 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
660 PROPVARIANT pos;
662 TRACE("%p.\n", iface);
664 pos.vt = VT_EMPTY;
665 return IMFMediaSession_Start(player->session, &GUID_NULL, &pos);
668 static HRESULT WINAPI media_player_Pause(IMFPMediaPlayer *iface)
670 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
672 TRACE("%p.\n", iface);
674 return IMFMediaSession_Pause(player->session);
677 static HRESULT WINAPI media_player_Stop(IMFPMediaPlayer *iface)
679 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
681 TRACE("%p.\n", iface);
683 return IMFMediaSession_Stop(player->session);
686 static HRESULT WINAPI media_player_FrameStep(IMFPMediaPlayer *iface)
688 FIXME("%p.\n", iface);
690 return E_NOTIMPL;
693 static HRESULT WINAPI media_player_SetPosition(IMFPMediaPlayer *iface, REFGUID postype, const PROPVARIANT *position)
695 FIXME("%p, %s, %p.\n", iface, debugstr_guid(postype), position);
697 return E_NOTIMPL;
700 static HRESULT WINAPI media_player_GetPosition(IMFPMediaPlayer *iface, REFGUID postype, PROPVARIANT *position)
702 FIXME("%p, %s, %p.\n", iface, debugstr_guid(postype), position);
704 return E_NOTIMPL;
707 static HRESULT WINAPI media_player_GetDuration(IMFPMediaPlayer *iface, REFGUID postype, PROPVARIANT *position)
709 FIXME("%p, %s, %p.\n", iface, debugstr_guid(postype), position);
711 return E_NOTIMPL;
714 static HRESULT WINAPI media_player_SetRate(IMFPMediaPlayer *iface, float rate)
716 FIXME("%p, %f.\n", iface, rate);
718 return E_NOTIMPL;
721 static HRESULT WINAPI media_player_GetRate(IMFPMediaPlayer *iface, float *rate)
723 FIXME("%p, %p.\n", iface, rate);
725 return E_NOTIMPL;
728 static HRESULT WINAPI media_player_GetSupportedRates(IMFPMediaPlayer *iface, BOOL forward,
729 float *slowest_rate, float *fastest_rate)
731 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
732 IMFRateSupport *rs;
733 HRESULT hr;
735 TRACE("%p, %d, %p, %p.\n", iface, forward, slowest_rate, fastest_rate);
737 if (SUCCEEDED(hr = MFGetService((IUnknown *)player->session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rs)))
739 if (SUCCEEDED(hr = IMFRateSupport_GetSlowestRate(rs, forward ? MFRATE_FORWARD : MFRATE_REVERSE, FALSE, slowest_rate)))
740 hr = IMFRateSupport_GetFastestRate(rs, forward ? MFRATE_FORWARD : MFRATE_REVERSE, FALSE, fastest_rate);
741 IMFRateSupport_Release(rs);
744 return hr;
747 static HRESULT WINAPI media_player_GetState(IMFPMediaPlayer *iface, MFP_MEDIAPLAYER_STATE *state)
749 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
751 TRACE("%p, %p.\n", iface, state);
753 *state = player->state;
755 return S_OK;
758 static HRESULT WINAPI media_player_CreateMediaItemFromURL(IMFPMediaPlayer *iface,
759 const WCHAR *url, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **ret)
761 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
762 struct media_item *item;
763 MF_OBJECT_TYPE obj_type;
764 IUnknown *object;
765 HRESULT hr;
767 TRACE("%p, %s, %d, %lx, %p.\n", iface, debugstr_w(url), sync, user_data, ret);
769 if (FAILED(hr = create_media_item(iface, user_data, &item)))
770 return hr;
772 if (sync)
774 *ret = NULL;
776 if (SUCCEEDED(hr = IMFSourceResolver_CreateObjectFromURL(player->resolver, url, MF_RESOLUTION_MEDIASOURCE,
777 player->propstore, &obj_type, &object)))
779 hr = media_item_set_source(item, object);
780 IUnknown_Release(object);
783 if (SUCCEEDED(hr))
784 *ret = &item->IMFPMediaItem_iface;
786 return hr;
788 else
790 hr = IMFSourceResolver_BeginCreateObjectFromURL(player->resolver, url, MF_RESOLUTION_MEDIASOURCE,
791 player->propstore, NULL, &player->resolver_callback, (IUnknown *)&item->IMFPMediaItem_iface);
793 IMFPMediaItem_Release(&item->IMFPMediaItem_iface);
796 return hr;
799 static HRESULT WINAPI media_player_CreateMediaItemFromObject(IMFPMediaPlayer *iface,
800 IUnknown *object, BOOL sync, DWORD_PTR user_data, IMFPMediaItem **item)
802 FIXME("%p, %p, %d, %lx, %p.\n", iface, object, sync, user_data, item);
804 return E_NOTIMPL;
807 static HRESULT WINAPI media_player_SetMediaItem(IMFPMediaPlayer *iface, IMFPMediaItem *item)
809 FIXME("%p, %p.\n", iface, item);
811 return E_NOTIMPL;
814 static HRESULT WINAPI media_player_ClearMediaItem(IMFPMediaPlayer *iface)
816 FIXME("%p.\n", iface);
818 return E_NOTIMPL;
821 static HRESULT WINAPI media_player_GetMediaItem(IMFPMediaPlayer *iface, IMFPMediaItem **item)
823 FIXME("%p, %p.\n", iface, item);
825 return E_NOTIMPL;
828 static HRESULT WINAPI media_player_GetVolume(IMFPMediaPlayer *iface, float *volume)
830 FIXME("%p, %p.\n", iface, volume);
832 return E_NOTIMPL;
835 static HRESULT WINAPI media_player_SetVolume(IMFPMediaPlayer *iface, float volume)
837 FIXME("%p, %.8e.\n", iface, volume);
839 return E_NOTIMPL;
842 static HRESULT WINAPI media_player_GetBalance(IMFPMediaPlayer *iface, float *balance)
844 FIXME("%p, %p.\n", iface, balance);
846 return E_NOTIMPL;
849 static HRESULT WINAPI media_player_SetBalance(IMFPMediaPlayer *iface, float balance)
851 FIXME("%p, %.8e.\n", iface, balance);
853 return E_NOTIMPL;
856 static HRESULT WINAPI media_player_GetMute(IMFPMediaPlayer *iface, BOOL *mute)
858 FIXME("%p, %p.\n", iface, mute);
860 return E_NOTIMPL;
863 static HRESULT WINAPI media_player_SetMute(IMFPMediaPlayer *iface, BOOL mute)
865 FIXME("%p, %d.\n", iface, mute);
867 return E_NOTIMPL;
870 static HRESULT WINAPI media_player_GetNativeVideoSize(IMFPMediaPlayer *iface,
871 SIZE *video, SIZE *arvideo)
873 FIXME("%p, %p, %p.\n", iface, video, arvideo);
875 return E_NOTIMPL;
878 static HRESULT WINAPI media_player_GetIdealVideoSize(IMFPMediaPlayer *iface,
879 SIZE *min_size, SIZE *max_size)
881 FIXME("%p, %p, %p.\n", iface, min_size, max_size);
883 return E_NOTIMPL;
886 static HRESULT WINAPI media_player_SetVideoSourceRect(IMFPMediaPlayer *iface,
887 MFVideoNormalizedRect const *rect)
889 FIXME("%p, %p.\n", iface, rect);
891 return E_NOTIMPL;
894 static HRESULT WINAPI media_player_GetVideoSourceRect(IMFPMediaPlayer *iface,
895 MFVideoNormalizedRect *rect)
897 FIXME("%p, %p.\n", iface, rect);
899 return E_NOTIMPL;
902 static HRESULT WINAPI media_player_SetAspectRatioMode(IMFPMediaPlayer *iface, DWORD mode)
904 FIXME("%p, %u.\n", iface, mode);
906 return E_NOTIMPL;
909 static HRESULT WINAPI media_player_GetAspectRatioMode(IMFPMediaPlayer *iface,
910 DWORD *mode)
912 FIXME("%p, %p.\n", iface, mode);
914 return E_NOTIMPL;
917 static HRESULT WINAPI media_player_GetVideoWindow(IMFPMediaPlayer *iface, HWND *window)
919 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
921 TRACE("%p, %p.\n", iface, window);
923 *window = player->output_window;
925 return S_OK;
928 static HRESULT WINAPI media_player_UpdateVideo(IMFPMediaPlayer *iface)
930 FIXME("%p.\n", iface);
932 return E_NOTIMPL;
935 static HRESULT WINAPI media_player_SetBorderColor(IMFPMediaPlayer *iface, COLORREF color)
937 FIXME("%p, %#x.\n", iface, color);
939 return E_NOTIMPL;
942 static HRESULT WINAPI media_player_GetBorderColor(IMFPMediaPlayer *iface, COLORREF *color)
944 FIXME("%p, %p.\n", iface, color);
946 return E_NOTIMPL;
949 static HRESULT WINAPI media_player_InsertEffect(IMFPMediaPlayer *iface, IUnknown *effect,
950 BOOL optional)
952 FIXME("%p, %p, %d.\n", iface, effect, optional);
954 return E_NOTIMPL;
957 static HRESULT WINAPI media_player_RemoveEffect(IMFPMediaPlayer *iface, IUnknown *effect)
959 FIXME("%p, %p.\n", iface, effect);
961 return E_NOTIMPL;
964 static HRESULT WINAPI media_player_RemoveAllEffects(IMFPMediaPlayer *iface)
966 FIXME("%p.\n", iface);
968 return E_NOTIMPL;
971 static HRESULT WINAPI media_player_Shutdown(IMFPMediaPlayer *iface)
973 struct media_player *player = impl_from_IMFPMediaPlayer(iface);
975 TRACE("%p.\n", iface);
977 EnterCriticalSection(&player->cs);
978 media_player_set_state(player, MFP_MEDIAPLAYER_STATE_SHUTDOWN);
979 LeaveCriticalSection(&player->cs);
981 return S_OK;
984 static const IMFPMediaPlayerVtbl media_player_vtbl =
986 media_player_QueryInterface,
987 media_player_AddRef,
988 media_player_Release,
989 media_player_Play,
990 media_player_Pause,
991 media_player_Stop,
992 media_player_FrameStep,
993 media_player_SetPosition,
994 media_player_GetPosition,
995 media_player_GetDuration,
996 media_player_SetRate,
997 media_player_GetRate,
998 media_player_GetSupportedRates,
999 media_player_GetState,
1000 media_player_CreateMediaItemFromURL,
1001 media_player_CreateMediaItemFromObject,
1002 media_player_SetMediaItem,
1003 media_player_ClearMediaItem,
1004 media_player_GetMediaItem,
1005 media_player_GetVolume,
1006 media_player_SetVolume,
1007 media_player_GetBalance,
1008 media_player_SetBalance,
1009 media_player_GetMute,
1010 media_player_SetMute,
1011 media_player_GetNativeVideoSize,
1012 media_player_GetIdealVideoSize,
1013 media_player_SetVideoSourceRect,
1014 media_player_GetVideoSourceRect,
1015 media_player_SetAspectRatioMode,
1016 media_player_GetAspectRatioMode,
1017 media_player_GetVideoWindow,
1018 media_player_UpdateVideo,
1019 media_player_SetBorderColor,
1020 media_player_GetBorderColor,
1021 media_player_InsertEffect,
1022 media_player_RemoveEffect,
1023 media_player_RemoveAllEffects,
1024 media_player_Shutdown,
1027 static HRESULT WINAPI media_player_propstore_QueryInterface(IPropertyStore *iface,
1028 REFIID riid, void **obj)
1030 struct media_player *player = impl_from_IPropertyStore(iface);
1031 return IMFPMediaPlayer_QueryInterface(&player->IMFPMediaPlayer_iface, riid, obj);
1034 static ULONG WINAPI media_player_propstore_AddRef(IPropertyStore *iface)
1036 struct media_player *player = impl_from_IPropertyStore(iface);
1037 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1040 static ULONG WINAPI media_player_propstore_Release(IPropertyStore *iface)
1042 struct media_player *player = impl_from_IPropertyStore(iface);
1043 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1046 static HRESULT WINAPI media_player_propstore_GetCount(IPropertyStore *iface, DWORD *count)
1048 struct media_player *player = impl_from_IPropertyStore(iface);
1050 TRACE("%p, %p.\n", iface, count);
1052 return IPropertyStore_GetCount(player->propstore, count);
1055 static HRESULT WINAPI media_player_propstore_GetAt(IPropertyStore *iface, DWORD prop, PROPERTYKEY *key)
1057 struct media_player *player = impl_from_IPropertyStore(iface);
1059 TRACE("%p, %u, %p.\n", iface, prop, key);
1061 return IPropertyStore_GetAt(player->propstore, prop, key);
1064 static HRESULT WINAPI media_player_propstore_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *value)
1066 struct media_player *player = impl_from_IPropertyStore(iface);
1068 TRACE("%p, %p, %p.\n", iface, key, value);
1070 return IPropertyStore_GetValue(player->propstore, key, value);
1073 static HRESULT WINAPI media_player_propstore_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT value)
1075 struct media_player *player = impl_from_IPropertyStore(iface);
1077 TRACE("%p, %p, %p.\n", iface, key, value);
1079 return IPropertyStore_SetValue(player->propstore, key, value);
1082 static HRESULT WINAPI media_player_propstore_Commit(IPropertyStore *iface)
1084 struct media_player *player = impl_from_IPropertyStore(iface);
1086 TRACE("%p.\n", iface);
1088 return IPropertyStore_Commit(player->propstore);
1091 static const IPropertyStoreVtbl media_player_propstore_vtbl =
1093 media_player_propstore_QueryInterface,
1094 media_player_propstore_AddRef,
1095 media_player_propstore_Release,
1096 media_player_propstore_GetCount,
1097 media_player_propstore_GetAt,
1098 media_player_propstore_GetValue,
1099 media_player_propstore_SetValue,
1100 media_player_propstore_Commit,
1103 static HRESULT WINAPI media_player_callback_QueryInterface(IMFAsyncCallback *iface,
1104 REFIID riid, void **obj)
1106 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
1107 IsEqualIID(riid, &IID_IUnknown))
1109 *obj = iface;
1110 IMFAsyncCallback_AddRef(iface);
1111 return S_OK;
1114 *obj = NULL;
1115 return E_NOINTERFACE;
1118 static ULONG WINAPI media_player_resolver_callback_AddRef(IMFAsyncCallback *iface)
1120 struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
1121 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1124 static ULONG WINAPI media_player_resolver_callback_Release(IMFAsyncCallback *iface)
1126 struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
1127 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1130 static HRESULT WINAPI media_player_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags,
1131 DWORD *queue)
1133 return E_NOTIMPL;
1136 static HRESULT WINAPI media_player_resolver_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1138 struct media_player *player = impl_from_resolver_IMFAsyncCallback(iface);
1139 struct media_event *event;
1140 IUnknown *object, *state;
1141 MF_OBJECT_TYPE obj_type;
1142 struct media_item *item;
1143 HRESULT hr;
1145 if (FAILED(IMFAsyncResult_GetState(result, &state)))
1146 return S_OK;
1148 item = impl_from_IMFPMediaItem((IMFPMediaItem *)state);
1150 if (SUCCEEDED(hr = IMFSourceResolver_EndCreateObjectFromURL(player->resolver, result, &obj_type, &object)))
1152 hr = media_item_set_source(item, object);
1153 IUnknown_Release(object);
1156 if (FAILED(hr))
1157 WARN("Failed to set media source, hr %#x.\n", hr);
1159 if (FAILED(media_event_create(player, MFP_EVENT_TYPE_MEDIAITEM_CREATED, hr, &event)))
1161 WARN("Failed to create event object.\n");
1162 IUnknown_Release(state);
1163 return S_OK;
1166 if (SUCCEEDED(hr))
1168 event->u.item_created.pMediaItem = &item->IMFPMediaItem_iface;
1169 IMFPMediaItem_AddRef(event->u.item_created.pMediaItem);
1171 event->u.item_created.dwUserData = item->user_data;
1173 media_player_queue_event(player, event);
1175 IUnknown_Release(&event->IUnknown_iface);
1176 IUnknown_Release(state);
1178 return S_OK;
1181 static const IMFAsyncCallbackVtbl media_player_resolver_callback_vtbl =
1183 media_player_callback_QueryInterface,
1184 media_player_resolver_callback_AddRef,
1185 media_player_resolver_callback_Release,
1186 media_player_callback_GetParameters,
1187 media_player_resolver_callback_Invoke,
1190 static ULONG WINAPI media_player_events_callback_AddRef(IMFAsyncCallback *iface)
1192 struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
1193 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1196 static ULONG WINAPI media_player_events_callback_Release(IMFAsyncCallback *iface)
1198 struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
1199 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1202 static HRESULT WINAPI media_player_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1204 struct media_player *player = impl_from_events_IMFAsyncCallback(iface);
1205 struct media_event *event;
1206 IUnknown *state;
1208 if (FAILED(IMFAsyncResult_GetState(result, &state)))
1209 return S_OK;
1211 event = impl_event_from_IUnknown(state);
1213 if (player->callback)
1214 IMFPMediaPlayerCallback_OnMediaPlayerEvent(player->callback, &event->u.header);
1216 IUnknown_Release(state);
1218 return S_OK;
1221 static const IMFAsyncCallbackVtbl media_player_events_callback_vtbl =
1223 media_player_callback_QueryInterface,
1224 media_player_events_callback_AddRef,
1225 media_player_events_callback_Release,
1226 media_player_callback_GetParameters,
1227 media_player_events_callback_Invoke,
1230 static ULONG WINAPI media_player_session_events_callback_AddRef(IMFAsyncCallback *iface)
1232 struct media_player *player = impl_from_session_events_IMFAsyncCallback(iface);
1233 return IMFPMediaPlayer_AddRef(&player->IMFPMediaPlayer_iface);
1236 static ULONG WINAPI media_player_session_events_callback_Release(IMFAsyncCallback *iface)
1238 struct media_player *player = impl_from_session_events_IMFAsyncCallback(iface);
1239 return IMFPMediaPlayer_Release(&player->IMFPMediaPlayer_iface);
1242 static HRESULT WINAPI media_player_session_events_callback_Invoke(IMFAsyncCallback *iface,
1243 IMFAsyncResult *result)
1245 struct media_player *player = impl_from_session_events_IMFAsyncCallback(iface);
1246 MediaEventType session_event_type = MEUnknown;
1247 struct media_event *event = NULL;
1248 IMFMediaEvent *session_event;
1249 MFP_MEDIAPLAYER_STATE state;
1250 MFP_EVENT_TYPE event_type;
1251 HRESULT hr, event_status;
1253 if (FAILED(hr = IMFMediaSession_EndGetEvent(player->session, result, &session_event)))
1254 return S_OK;
1256 IMFMediaEvent_GetType(session_event, &session_event_type);
1257 IMFMediaEvent_GetStatus(session_event, &event_status);
1259 switch (session_event_type)
1261 case MESessionStarted:
1262 case MESessionStopped:
1263 case MESessionPaused:
1264 if (session_event_type == MESessionStarted)
1266 event_type = MFP_EVENT_TYPE_PLAY;
1267 state = MFP_MEDIAPLAYER_STATE_PLAYING;
1269 else if (session_event_type == MESessionStopped)
1271 event_type = MFP_EVENT_TYPE_STOP;
1272 state = MFP_MEDIAPLAYER_STATE_STOPPED;
1274 else
1276 event_type = MFP_EVENT_TYPE_PAUSE;
1277 state = MFP_MEDIAPLAYER_STATE_PAUSED;
1280 EnterCriticalSection(&player->cs);
1281 media_player_set_state(player, state);
1282 media_event_create(player, event_type, event_status, &event);
1283 LeaveCriticalSection(&player->cs);
1285 /* FIXME: set pMediaItem */
1286 media_player_queue_event(player, event);
1287 IUnknown_Release(&event->IUnknown_iface);
1289 break;
1290 default:
1294 if (event)
1296 IUnknown_Release(&event->IUnknown_iface);
1299 IMFMediaSession_BeginGetEvent(player->session, &player->session_events_callback, NULL);
1300 IMFMediaEvent_Release(session_event);
1302 return S_OK;
1305 static const IMFAsyncCallbackVtbl media_player_session_events_callback_vtbl =
1307 media_player_callback_QueryInterface,
1308 media_player_session_events_callback_AddRef,
1309 media_player_session_events_callback_Release,
1310 media_player_callback_GetParameters,
1311 media_player_session_events_callback_Invoke,
1314 HRESULT WINAPI MFPCreateMediaPlayer(const WCHAR *url, BOOL start_playback, MFP_CREATION_OPTIONS options,
1315 IMFPMediaPlayerCallback *callback, HWND window, IMFPMediaPlayer **player)
1317 struct media_player *object;
1318 HRESULT hr;
1320 TRACE("%s, %d, %#x, %p, %p, %p.\n", debugstr_w(url), start_playback, options, callback, window, player);
1322 if (!(object = heap_alloc_zero(sizeof(*object))))
1323 return E_OUTOFMEMORY;
1325 platform_startup();
1327 object->IMFPMediaPlayer_iface.lpVtbl = &media_player_vtbl;
1328 object->IPropertyStore_iface.lpVtbl = &media_player_propstore_vtbl;
1329 object->resolver_callback.lpVtbl = &media_player_resolver_callback_vtbl;
1330 object->events_callback.lpVtbl = &media_player_events_callback_vtbl;
1331 object->session_events_callback.lpVtbl = &media_player_session_events_callback_vtbl;
1332 object->refcount = 1;
1333 object->callback = callback;
1334 if (object->callback)
1335 IMFPMediaPlayerCallback_AddRef(object->callback);
1336 object->options = options;
1337 object->output_window = window;
1338 InitializeCriticalSection(&object->cs);
1339 if (FAILED(hr = CreatePropertyStore(&object->propstore)))
1340 goto failed;
1341 if (FAILED(hr = MFCreateSourceResolver(&object->resolver)))
1342 goto failed;
1343 if (FAILED(hr = MFCreateMediaSession(NULL, &object->session)))
1344 goto failed;
1345 if (FAILED(hr = IMFMediaSession_BeginGetEvent(object->session, &object->session_events_callback, NULL)))
1346 goto failed;
1347 if (!(object->options & MFP_OPTION_FREE_THREADED_CALLBACK))
1349 object->event_window = CreateWindowW(eventclassW, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE,
1350 0, mfplay_instance, NULL);
1353 *player = &object->IMFPMediaPlayer_iface;
1355 return S_OK;
1357 failed:
1359 IMFPMediaPlayer_Release(&object->IMFPMediaPlayer_iface);
1361 return hr;
1364 static void media_player_register_window_class(void)
1366 WNDCLASSW cls = { 0 };
1368 cls.lpfnWndProc = media_player_event_proc;
1369 cls.hInstance = mfplay_instance;
1370 cls.lpszClassName = eventclassW;
1372 RegisterClassW(&cls);
1375 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
1377 switch (reason)
1379 case DLL_PROCESS_ATTACH:
1380 mfplay_instance = instance;
1381 DisableThreadLibraryCalls(instance);
1382 media_player_register_window_class();
1383 break;
1384 case DLL_PROCESS_DETACH:
1385 if (reserved) break;
1386 UnregisterClassW(eventclassW, instance);
1387 break;
1390 return TRUE;