mfmediaengine: Implement GetCurrentSource().
[wine.git] / dlls / mfmediaengine / main.c
blob2f4a38936c4d344e9ff584f97c6c53ef81ad35a0
1 /*
2 * Copyright 2019 Jactry Zeng 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 <math.h>
22 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
27 #include "mfapi.h"
28 #include "mfmediaengine.h"
29 #include "mferror.h"
30 #include "dxgi.h"
32 #include "wine/debug.h"
33 #include "wine/heap.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
37 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
39 switch (reason)
41 case DLL_WINE_PREATTACH:
42 return FALSE; /* prefer native version */
43 case DLL_PROCESS_ATTACH:
44 DisableThreadLibraryCalls(instance);
45 break;
48 return TRUE;
51 enum media_engine_mode
53 MEDIA_ENGINE_INVALID,
54 MEDIA_ENGINE_AUDIO_MODE,
55 MEDIA_ENGINE_RENDERING_MODE,
56 MEDIA_ENGINE_FRAME_SERVER_MODE,
59 /* Used with create flags. */
60 enum media_engine_flags
62 /* MF_MEDIA_ENGINE_CREATEFLAGS_MASK is 0x1f. */
63 FLAGS_ENGINE_SHUT_DOWN = 0x20,
64 FLAGS_ENGINE_AUTO_PLAY = 0x40,
65 FLAGS_ENGINE_LOOP = 0x80,
66 FLAGS_ENGINE_PAUSED = 0x100,
67 FLAGS_ENGINE_WAITING = 0x200,
68 FLAGS_ENGINE_MUTED = 0x400,
69 FLAGS_ENGINE_HAS_AUDIO = 0x800,
70 FLAGS_ENGINE_HAS_VIDEO = 0x1000,
73 struct media_engine
75 IMFMediaEngine IMFMediaEngine_iface;
76 IMFAsyncCallback session_events;
77 IMFAsyncCallback load_handler;
78 LONG refcount;
79 IMFMediaEngineNotify *callback;
80 IMFAttributes *attributes;
81 enum media_engine_mode mode;
82 unsigned int flags;
83 double playback_rate;
84 double default_playback_rate;
85 double volume;
86 double duration;
87 MF_MEDIA_ENGINE_ERR error_code;
88 HRESULT extended_code;
89 IMFMediaSession *session;
90 IMFSourceResolver *resolver;
91 BSTR current_source;
92 CRITICAL_SECTION cs;
95 struct media_error
97 IMFMediaError IMFMediaError_iface;
98 LONG refcount;
99 unsigned int code;
100 HRESULT extended_code;
103 static struct media_error *impl_from_IMFMediaError(IMFMediaError *iface)
105 return CONTAINING_RECORD(iface, struct media_error, IMFMediaError_iface);
108 static HRESULT WINAPI media_error_QueryInterface(IMFMediaError *iface, REFIID riid, void **obj)
110 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
112 if (IsEqualIID(riid, &IID_IMFMediaError) ||
113 IsEqualIID(riid, &IID_IUnknown))
115 *obj = iface;
116 IMFMediaError_AddRef(iface);
117 return S_OK;
120 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
121 *obj = NULL;
122 return E_NOINTERFACE;
125 static ULONG WINAPI media_error_AddRef(IMFMediaError *iface)
127 struct media_error *me = impl_from_IMFMediaError(iface);
128 ULONG refcount = InterlockedIncrement(&me->refcount);
130 TRACE("%p, refcount %u.\n", iface, refcount);
132 return refcount;
135 static ULONG WINAPI media_error_Release(IMFMediaError *iface)
137 struct media_error *me = impl_from_IMFMediaError(iface);
138 ULONG refcount = InterlockedDecrement(&me->refcount);
140 TRACE("%p, refcount %u.\n", iface, refcount);
142 if (!refcount)
143 heap_free(me);
145 return refcount;
148 static USHORT WINAPI media_error_GetErrorCode(IMFMediaError *iface)
150 struct media_error *me = impl_from_IMFMediaError(iface);
151 TRACE("%p.\n", iface);
152 return me->code;
155 static HRESULT WINAPI media_error_GetExtendedErrorCode(IMFMediaError *iface)
157 struct media_error *me = impl_from_IMFMediaError(iface);
158 TRACE("%p.\n", iface);
159 return me->extended_code;
162 static HRESULT WINAPI media_error_SetErrorCode(IMFMediaError *iface, MF_MEDIA_ENGINE_ERR code)
164 struct media_error *me = impl_from_IMFMediaError(iface);
166 TRACE("%p, %u.\n", iface, code);
168 if ((unsigned int)code > MF_MEDIA_ENGINE_ERR_ENCRYPTED)
169 return E_INVALIDARG;
171 me->code = code;
173 return S_OK;
176 static HRESULT WINAPI media_error_SetExtendedErrorCode(IMFMediaError *iface, HRESULT code)
178 struct media_error *me = impl_from_IMFMediaError(iface);
180 TRACE("%p, %#x.\n", iface, code);
182 me->extended_code = code;
184 return S_OK;
187 static const IMFMediaErrorVtbl media_error_vtbl =
189 media_error_QueryInterface,
190 media_error_AddRef,
191 media_error_Release,
192 media_error_GetErrorCode,
193 media_error_GetExtendedErrorCode,
194 media_error_SetErrorCode,
195 media_error_SetExtendedErrorCode,
198 static HRESULT create_media_error(IMFMediaError **ret)
200 struct media_error *object;
202 *ret = NULL;
204 if (!(object = heap_alloc_zero(sizeof(*object))))
205 return E_OUTOFMEMORY;
207 object->IMFMediaError_iface.lpVtbl = &media_error_vtbl;
208 object->refcount = 1;
210 *ret = &object->IMFMediaError_iface;
212 return S_OK;
215 static void media_engine_set_flag(struct media_engine *engine, unsigned int mask, BOOL value)
217 if (value)
218 engine->flags |= mask;
219 else
220 engine->flags &= ~mask;
223 static inline struct media_engine *impl_from_IMFMediaEngine(IMFMediaEngine *iface)
225 return CONTAINING_RECORD(iface, struct media_engine, IMFMediaEngine_iface);
228 static struct media_engine *impl_from_session_events_IMFAsyncCallback(IMFAsyncCallback *iface)
230 return CONTAINING_RECORD(iface, struct media_engine, session_events);
233 static struct media_engine *impl_from_load_handler_IMFAsyncCallback(IMFAsyncCallback *iface)
235 return CONTAINING_RECORD(iface, struct media_engine, load_handler);
238 static HRESULT WINAPI media_engine_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
240 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
241 IsEqualIID(riid, &IID_IUnknown))
243 *obj = iface;
244 IMFAsyncCallback_AddRef(iface);
245 return S_OK;
248 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
249 *obj = NULL;
250 return E_NOINTERFACE;
253 static ULONG WINAPI media_engine_session_events_AddRef(IMFAsyncCallback *iface)
255 struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
256 return IMFMediaEngine_AddRef(&engine->IMFMediaEngine_iface);
259 static ULONG WINAPI media_engine_session_events_Release(IMFAsyncCallback *iface)
261 struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
262 return IMFMediaEngine_Release(&engine->IMFMediaEngine_iface);
265 static HRESULT WINAPI media_engine_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
267 return E_NOTIMPL;
270 static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
272 struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
273 IMFMediaEvent *event = NULL;
274 MediaEventType event_type;
275 HRESULT hr;
277 if (FAILED(hr = IMFMediaSession_EndGetEvent(engine->session, result, &event)))
279 WARN("Failed to get session event, hr %#x.\n", hr);
280 goto failed;
283 if (FAILED(hr = IMFMediaEvent_GetType(event, &event_type)))
285 WARN("Failed to get event type, hr %#x.\n", hr);
286 goto failed;
289 switch (event_type)
291 case MEBufferingStarted:
292 case MEBufferingStopped:
294 IMFMediaEngineNotify_EventNotify(engine->callback, event_type == MEBufferingStarted ?
295 MF_MEDIA_ENGINE_EVENT_BUFFERINGSTARTED : MF_MEDIA_ENGINE_EVENT_BUFFERINGENDED, 0, 0);
296 break;
299 failed:
301 if (event)
302 IMFMediaEvent_Release(event);
304 if (FAILED(hr = IMFMediaSession_BeginGetEvent(engine->session, iface, NULL)))
305 WARN("Failed to subscribe to session events, hr %#x.\n", hr);
307 return S_OK;
310 static const IMFAsyncCallbackVtbl media_engine_session_events_vtbl =
312 media_engine_callback_QueryInterface,
313 media_engine_session_events_AddRef,
314 media_engine_session_events_Release,
315 media_engine_callback_GetParameters,
316 media_engine_session_events_Invoke,
319 static ULONG WINAPI media_engine_load_handler_AddRef(IMFAsyncCallback *iface)
321 struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
322 return IMFMediaEngine_AddRef(&engine->IMFMediaEngine_iface);
325 static ULONG WINAPI media_engine_load_handler_Release(IMFAsyncCallback *iface)
327 struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
328 return IMFMediaEngine_Release(&engine->IMFMediaEngine_iface);
331 static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMediaSource *source)
333 IMFStreamDescriptor *sd_audio = NULL, *sd_video = NULL;
334 unsigned int stream_count = 0, i;
335 IMFPresentationDescriptor *pd;
336 UINT64 duration;
337 HRESULT hr;
339 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd)))
340 return hr;
342 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(pd, &stream_count)))
343 WARN("Failed to get stream count, hr %#x.\n", hr);
345 /* Enable first video stream and first audio stream. */
347 for (i = 0; i < stream_count; ++i)
349 IMFMediaTypeHandler *type_handler;
350 IMFStreamDescriptor *sd;
351 BOOL selected;
353 IMFPresentationDescriptor_DeselectStream(pd, i);
355 if (sd_audio && sd_video)
356 continue;
358 IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, i, &selected, &sd);
360 if (SUCCEEDED(IMFStreamDescriptor_GetMediaTypeHandler(sd, &type_handler)))
362 GUID major = { 0 };
364 IMFMediaTypeHandler_GetMajorType(type_handler, &major);
366 if (IsEqualGUID(&major, &MFMediaType_Audio) && !sd_audio)
368 sd_audio = sd;
369 IMFStreamDescriptor_AddRef(sd_audio);
370 IMFPresentationDescriptor_SelectStream(pd, i);
372 else if (IsEqualGUID(&major, &MFMediaType_Video) && !sd_video && !(engine->flags & MF_MEDIA_ENGINE_AUDIOONLY))
374 sd_video = sd;
375 IMFStreamDescriptor_AddRef(sd_video);
376 IMFPresentationDescriptor_SelectStream(pd, i);
379 IMFMediaTypeHandler_Release(type_handler);
383 if (!sd_video && !sd_audio)
385 IMFPresentationDescriptor_Release(pd);
386 return E_UNEXPECTED;
389 if (sd_video)
390 engine->flags |= FLAGS_ENGINE_HAS_VIDEO;
391 if (sd_audio)
392 engine->flags |= FLAGS_ENGINE_HAS_AUDIO;
394 /* Assume live source if duration was not provided. */
395 if (SUCCEEDED(IMFPresentationDescriptor_GetUINT64(pd, &MF_PD_DURATION, &duration)))
397 /* Convert 100ns to seconds. */
398 engine->duration = duration / 10000000;
400 else
401 engine->duration = INFINITY;
403 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE, 0, 0);
404 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA, 0, 0);
405 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDDATA, 0, 0);
407 /* TODO: set up topology nodes */
409 if (sd_video)
410 IMFStreamDescriptor_Release(sd_video);
411 if (sd_audio)
412 IMFStreamDescriptor_Release(sd_audio);
414 IMFPresentationDescriptor_Release(pd);
416 return S_OK;
419 static HRESULT WINAPI media_engine_load_handler_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
421 struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
422 MF_OBJECT_TYPE obj_type;
423 IMFMediaSource *source;
424 IUnknown *object = NULL;
425 HRESULT hr;
427 EnterCriticalSection(&engine->cs);
429 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADSTART, 0, 0);
431 if (FAILED(hr = IMFSourceResolver_EndCreateObjectFromURL(engine->resolver, result, &obj_type, &object)))
432 WARN("Failed to create source object, hr %#x.\n", hr);
434 if (object)
436 if (SUCCEEDED(hr = IUnknown_QueryInterface(object, &IID_IMFMediaSource, (void **)&source)))
438 hr = media_engine_create_topology(engine, source);
439 IMFMediaSource_Release(source);
441 IUnknown_Release(object);
444 if (FAILED(hr))
446 engine->error_code = MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED;
447 engine->extended_code = hr;
448 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ERROR, engine->error_code,
449 engine->extended_code);
452 LeaveCriticalSection(&engine->cs);
454 return S_OK;
457 static const IMFAsyncCallbackVtbl media_engine_load_handler_vtbl =
459 media_engine_callback_QueryInterface,
460 media_engine_load_handler_AddRef,
461 media_engine_load_handler_Release,
462 media_engine_callback_GetParameters,
463 media_engine_load_handler_Invoke,
466 static HRESULT WINAPI media_engine_QueryInterface(IMFMediaEngine *iface, REFIID riid, void **obj)
468 TRACE("(%p, %s, %p).\n", iface, debugstr_guid(riid), obj);
470 if (IsEqualIID(riid, &IID_IMFMediaEngine) ||
471 IsEqualIID(riid, &IID_IUnknown))
473 *obj = iface;
474 IMFMediaEngine_AddRef(iface);
475 return S_OK;
478 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
479 *obj = NULL;
480 return E_NOINTERFACE;
483 static ULONG WINAPI media_engine_AddRef(IMFMediaEngine *iface)
485 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
486 ULONG refcount = InterlockedIncrement(&engine->refcount);
488 TRACE("(%p) ref=%u.\n", iface, refcount);
490 return refcount;
493 static void free_media_engine(struct media_engine *engine)
495 if (engine->callback)
496 IMFMediaEngineNotify_Release(engine->callback);
497 if (engine->session)
498 IMFMediaSession_Release(engine->session);
499 if (engine->attributes)
500 IMFAttributes_Release(engine->attributes);
501 if (engine->resolver)
502 IMFSourceResolver_Release(engine->resolver);
503 SysFreeString(engine->current_source);
504 DeleteCriticalSection(&engine->cs);
505 heap_free(engine);
508 static ULONG WINAPI media_engine_Release(IMFMediaEngine *iface)
510 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
511 ULONG refcount = InterlockedDecrement(&engine->refcount);
513 TRACE("(%p) ref=%u.\n", iface, refcount);
515 if (!refcount)
516 free_media_engine(engine);
518 return refcount;
521 static HRESULT WINAPI media_engine_GetError(IMFMediaEngine *iface, IMFMediaError **error)
523 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
524 HRESULT hr = S_OK;
526 TRACE("%p, %p.\n", iface, error);
528 *error = NULL;
530 EnterCriticalSection(&engine->cs);
531 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
532 hr = MF_E_SHUTDOWN;
533 else if (engine->error_code)
535 if (SUCCEEDED(hr = create_media_error(error)))
537 IMFMediaError_SetErrorCode(*error, engine->error_code);
538 IMFMediaError_SetExtendedErrorCode(*error, engine->extended_code);
541 LeaveCriticalSection(&engine->cs);
543 return hr;
546 static HRESULT WINAPI media_engine_SetErrorCode(IMFMediaEngine *iface, MF_MEDIA_ENGINE_ERR code)
548 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
549 HRESULT hr = S_OK;
551 TRACE("%p, %u.\n", iface, code);
553 if ((unsigned int)code > MF_MEDIA_ENGINE_ERR_ENCRYPTED)
554 return E_INVALIDARG;
556 EnterCriticalSection(&engine->cs);
557 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
558 hr = MF_E_SHUTDOWN;
559 else
560 engine->error_code = code;
561 LeaveCriticalSection(&engine->cs);
563 return hr;
566 static HRESULT WINAPI media_engine_SetSourceElements(IMFMediaEngine *iface, IMFMediaEngineSrcElements *elements)
568 FIXME("(%p, %p): stub.\n", iface, elements);
570 return E_NOTIMPL;
573 static HRESULT WINAPI media_engine_SetSource(IMFMediaEngine *iface, BSTR url)
575 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
576 HRESULT hr = S_OK;
578 TRACE("%p, %s.\n", iface, debugstr_w(url));
580 EnterCriticalSection(&engine->cs);
582 SysFreeString(engine->current_source);
583 engine->current_source = NULL;
584 if (url)
585 engine->current_source = SysAllocString(url);
587 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
589 if (url)
591 IPropertyStore *props = NULL;
592 unsigned int flags;
594 flags = MF_RESOLUTION_MEDIASOURCE;
595 if (engine->flags & MF_MEDIA_ENGINE_DISABLE_LOCAL_PLUGINS)
596 flags |= MF_RESOLUTION_DISABLE_LOCAL_PLUGINS;
598 IMFAttributes_GetUnknown(engine->attributes, &MF_MEDIA_ENGINE_SOURCE_RESOLVER_CONFIG_STORE,
599 &IID_IPropertyStore, (void **)&props);
600 hr = IMFSourceResolver_BeginCreateObjectFromURL(engine->resolver, url, flags, props, NULL, &engine->load_handler, NULL);
601 if (props)
602 IPropertyStore_Release(props);
605 LeaveCriticalSection(&engine->cs);
607 return hr;
610 static HRESULT WINAPI media_engine_GetCurrentSource(IMFMediaEngine *iface, BSTR *url)
612 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
613 HRESULT hr = S_OK;
615 TRACE("%p, %p.\n", iface, url);
617 *url = NULL;
619 EnterCriticalSection(&engine->cs);
620 if (engine->current_source)
622 if (!(*url = SysAllocString(engine->current_source)))
623 hr = E_OUTOFMEMORY;
625 LeaveCriticalSection(&engine->cs);
627 return hr;
630 static USHORT WINAPI media_engine_GetNetworkState(IMFMediaEngine *iface)
632 FIXME("(%p): stub.\n", iface);
634 return 0;
637 static MF_MEDIA_ENGINE_PRELOAD WINAPI media_engine_GetPreload(IMFMediaEngine *iface)
639 FIXME("(%p): stub.\n", iface);
641 return MF_MEDIA_ENGINE_PRELOAD_NONE;
644 static HRESULT WINAPI media_engine_SetPreload(IMFMediaEngine *iface, MF_MEDIA_ENGINE_PRELOAD preload)
646 FIXME("(%p, %d): stub.\n", iface, preload);
648 return E_NOTIMPL;
651 static HRESULT WINAPI media_engine_GetBuffered(IMFMediaEngine *iface, IMFMediaTimeRange **buffered)
653 FIXME("(%p, %p): stub.\n", iface, buffered);
655 return E_NOTIMPL;
658 static HRESULT WINAPI media_engine_Load(IMFMediaEngine *iface)
660 FIXME("(%p): stub.\n", iface);
662 return E_NOTIMPL;
665 static HRESULT WINAPI media_engine_CanPlayType(IMFMediaEngine *iface, BSTR type, MF_MEDIA_ENGINE_CANPLAY *answer)
667 FIXME("(%p, %s, %p): stub.\n", iface, debugstr_w(type), answer);
669 return E_NOTIMPL;
672 static USHORT WINAPI media_engine_GetReadyState(IMFMediaEngine *iface)
674 FIXME("(%p): stub.\n", iface);
676 return 0;
679 static BOOL WINAPI media_engine_IsSeeking(IMFMediaEngine *iface)
681 FIXME("(%p): stub.\n", iface);
683 return FALSE;
686 static double WINAPI media_engine_GetCurrentTime(IMFMediaEngine *iface)
688 FIXME("(%p): stub.\n", iface);
690 return 0.0;
693 static HRESULT WINAPI media_engine_SetCurrentTime(IMFMediaEngine *iface, double time)
695 FIXME("(%p, %f): stub.\n", iface, time);
697 return E_NOTIMPL;
700 static double WINAPI media_engine_GetStartTime(IMFMediaEngine *iface)
702 FIXME("(%p): stub.\n", iface);
704 return 0.0;
707 static double WINAPI media_engine_GetDuration(IMFMediaEngine *iface)
709 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
710 double value;
712 TRACE("%p.\n", iface);
714 EnterCriticalSection(&engine->cs);
715 value = engine->duration;
716 LeaveCriticalSection(&engine->cs);
718 return value;
721 static BOOL WINAPI media_engine_IsPaused(IMFMediaEngine *iface)
723 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
724 BOOL value;
726 TRACE("%p.\n", iface);
728 EnterCriticalSection(&engine->cs);
729 value = !!(engine->flags & FLAGS_ENGINE_PAUSED);
730 LeaveCriticalSection(&engine->cs);
732 return value;
735 static double WINAPI media_engine_GetDefaultPlaybackRate(IMFMediaEngine *iface)
737 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
738 double rate;
740 TRACE("%p.\n", iface);
742 EnterCriticalSection(&engine->cs);
743 rate = engine->default_playback_rate;
744 LeaveCriticalSection(&engine->cs);
746 return rate;
749 static HRESULT WINAPI media_engine_SetDefaultPlaybackRate(IMFMediaEngine *iface, double rate)
751 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
752 HRESULT hr = S_OK;
754 TRACE("%p, %f.\n", iface, rate);
756 EnterCriticalSection(&engine->cs);
757 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
758 hr = MF_E_SHUTDOWN;
759 else if (engine->default_playback_rate != rate)
761 engine->default_playback_rate = rate;
762 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_RATECHANGE, 0, 0);
764 LeaveCriticalSection(&engine->cs);
766 return hr;
769 static double WINAPI media_engine_GetPlaybackRate(IMFMediaEngine *iface)
771 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
772 double rate;
774 TRACE("%p.\n", iface);
776 EnterCriticalSection(&engine->cs);
777 rate = engine->playback_rate;
778 LeaveCriticalSection(&engine->cs);
780 return rate;
783 static HRESULT WINAPI media_engine_SetPlaybackRate(IMFMediaEngine *iface, double rate)
785 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
786 HRESULT hr = S_OK;
788 TRACE("%p, %f.\n", iface, rate);
790 EnterCriticalSection(&engine->cs);
791 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
792 hr = MF_E_SHUTDOWN;
793 else if (engine->playback_rate != rate)
795 engine->playback_rate = rate;
796 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_RATECHANGE, 0, 0);
798 LeaveCriticalSection(&engine->cs);
800 return hr;
803 static HRESULT WINAPI media_engine_GetPlayed(IMFMediaEngine *iface, IMFMediaTimeRange **played)
805 FIXME("(%p, %p): stub.\n", iface, played);
807 return E_NOTIMPL;
810 static HRESULT WINAPI media_engine_GetSeekable(IMFMediaEngine *iface, IMFMediaTimeRange **seekable)
812 FIXME("(%p, %p): stub.\n", iface, seekable);
814 return E_NOTIMPL;
817 static BOOL WINAPI media_engine_IsEnded(IMFMediaEngine *iface)
819 FIXME("(%p): stub.\n", iface);
821 return FALSE;
824 static BOOL WINAPI media_engine_GetAutoPlay(IMFMediaEngine *iface)
826 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
827 BOOL value;
829 TRACE("%p.\n", iface);
831 EnterCriticalSection(&engine->cs);
832 value = !!(engine->flags & FLAGS_ENGINE_AUTO_PLAY);
833 LeaveCriticalSection(&engine->cs);
835 return value;
838 static HRESULT WINAPI media_engine_SetAutoPlay(IMFMediaEngine *iface, BOOL autoplay)
840 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
842 FIXME("(%p, %d): stub.\n", iface, autoplay);
844 EnterCriticalSection(&engine->cs);
845 media_engine_set_flag(engine, FLAGS_ENGINE_AUTO_PLAY, autoplay);
846 LeaveCriticalSection(&engine->cs);
848 return S_OK;
851 static BOOL WINAPI media_engine_GetLoop(IMFMediaEngine *iface)
853 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
854 BOOL value;
856 TRACE("%p.\n", iface);
858 EnterCriticalSection(&engine->cs);
859 value = !!(engine->flags & FLAGS_ENGINE_LOOP);
860 LeaveCriticalSection(&engine->cs);
862 return value;
865 static HRESULT WINAPI media_engine_SetLoop(IMFMediaEngine *iface, BOOL loop)
867 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
869 FIXME("(%p, %d): stub.\n", iface, loop);
871 EnterCriticalSection(&engine->cs);
872 media_engine_set_flag(engine, FLAGS_ENGINE_LOOP, loop);
873 LeaveCriticalSection(&engine->cs);
875 return S_OK;
878 static HRESULT WINAPI media_engine_Play(IMFMediaEngine *iface)
880 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
881 PROPVARIANT var;
883 TRACE("%p.\n", iface);
885 EnterCriticalSection(&engine->cs);
887 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
889 if (!(engine->flags & FLAGS_ENGINE_WAITING))
891 engine->flags &= ~FLAGS_ENGINE_PAUSED;
892 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PLAY, 0, 0);
894 var.vt = VT_EMPTY;
895 IMFMediaSession_Start(engine->session, &GUID_NULL, &var);
897 engine->flags |= FLAGS_ENGINE_WAITING;
900 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_WAITING, 0, 0);
902 LeaveCriticalSection(&engine->cs);
904 return S_OK;
907 static HRESULT WINAPI media_engine_Pause(IMFMediaEngine *iface)
909 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
911 TRACE("%p.\n", iface);
913 EnterCriticalSection(&engine->cs);
915 if (!(engine->flags & FLAGS_ENGINE_PAUSED))
917 engine->flags &= ~FLAGS_ENGINE_WAITING;
918 engine->flags |= FLAGS_ENGINE_PAUSED;
920 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_TIMEUPDATE, 0, 0);
921 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PAUSE, 0, 0);
924 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
926 LeaveCriticalSection(&engine->cs);
928 return S_OK;
931 static BOOL WINAPI media_engine_GetMuted(IMFMediaEngine *iface)
933 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
934 BOOL ret;
936 TRACE("%p.\n", iface);
938 EnterCriticalSection(&engine->cs);
939 ret = !!(engine->flags & FLAGS_ENGINE_MUTED);
940 LeaveCriticalSection(&engine->cs);
942 return ret;
945 static HRESULT WINAPI media_engine_SetMuted(IMFMediaEngine *iface, BOOL muted)
947 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
948 HRESULT hr = S_OK;
950 TRACE("%p, %d.\n", iface, muted);
952 EnterCriticalSection(&engine->cs);
953 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
954 hr = MF_E_SHUTDOWN;
955 else if (!!(engine->flags & FLAGS_ENGINE_MUTED) ^ !!muted)
957 media_engine_set_flag(engine, FLAGS_ENGINE_MUTED, muted);
958 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE, 0, 0);
960 LeaveCriticalSection(&engine->cs);
962 return hr;
965 static double WINAPI media_engine_GetVolume(IMFMediaEngine *iface)
967 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
968 double volume;
970 TRACE("%p.\n", iface);
972 EnterCriticalSection(&engine->cs);
973 volume = engine->volume;
974 LeaveCriticalSection(&engine->cs);
976 return volume;
979 static HRESULT WINAPI media_engine_SetVolume(IMFMediaEngine *iface, double volume)
981 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
982 HRESULT hr = S_OK;
984 TRACE("%p, %f.\n", iface, volume);
986 EnterCriticalSection(&engine->cs);
987 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
988 hr = MF_E_SHUTDOWN;
989 else if (volume != engine->volume)
991 engine->volume = volume;
992 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE, 0, 0);
994 LeaveCriticalSection(&engine->cs);
996 return hr;
999 static BOOL WINAPI media_engine_HasVideo(IMFMediaEngine *iface)
1001 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1002 BOOL value;
1004 TRACE("%p.\n", iface);
1006 EnterCriticalSection(&engine->cs);
1007 value = !!(engine->flags & FLAGS_ENGINE_HAS_VIDEO);
1008 LeaveCriticalSection(&engine->cs);
1010 return value;
1013 static BOOL WINAPI media_engine_HasAudio(IMFMediaEngine *iface)
1015 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1016 BOOL value;
1018 TRACE("%p.\n", iface);
1020 EnterCriticalSection(&engine->cs);
1021 value = !!(engine->flags & FLAGS_ENGINE_HAS_AUDIO);
1022 LeaveCriticalSection(&engine->cs);
1024 return value;
1027 static HRESULT WINAPI media_engine_GetNativeVideoSize(IMFMediaEngine *iface, DWORD *cx, DWORD *cy)
1029 FIXME("(%p, %p, %p): stub.\n", iface, cx, cy);
1031 return E_NOTIMPL;
1034 static HRESULT WINAPI media_engine_GetVideoAspectRatio(IMFMediaEngine *iface, DWORD *cx, DWORD *cy)
1036 FIXME("(%p, %p, %p): stub.\n", iface, cx, cy);
1038 return E_NOTIMPL;
1041 static HRESULT WINAPI media_engine_Shutdown(IMFMediaEngine *iface)
1043 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1044 HRESULT hr = S_OK;
1046 FIXME("(%p): stub.\n", iface);
1048 EnterCriticalSection(&engine->cs);
1049 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1050 hr = MF_E_SHUTDOWN;
1051 else
1053 engine->flags |= FLAGS_ENGINE_SHUT_DOWN;
1054 IMFMediaSession_Shutdown(engine->session);
1056 LeaveCriticalSection(&engine->cs);
1058 return hr;
1061 static HRESULT WINAPI media_engine_TransferVideoFrame(IMFMediaEngine *iface, IUnknown *surface,
1062 const MFVideoNormalizedRect *src,
1063 const RECT *dst, const MFARGB *color)
1065 FIXME("(%p, %p, %p, %p, %p): stub.\n", iface, surface, src, dst, color);
1067 return E_NOTIMPL;
1070 static HRESULT WINAPI media_engine_OnVideoStreamTick(IMFMediaEngine *iface, LONGLONG *time)
1072 FIXME("(%p, %p): stub.\n", iface, time);
1074 return E_NOTIMPL;
1077 static const IMFMediaEngineVtbl media_engine_vtbl =
1079 media_engine_QueryInterface,
1080 media_engine_AddRef,
1081 media_engine_Release,
1082 media_engine_GetError,
1083 media_engine_SetErrorCode,
1084 media_engine_SetSourceElements,
1085 media_engine_SetSource,
1086 media_engine_GetCurrentSource,
1087 media_engine_GetNetworkState,
1088 media_engine_GetPreload,
1089 media_engine_SetPreload,
1090 media_engine_GetBuffered,
1091 media_engine_Load,
1092 media_engine_CanPlayType,
1093 media_engine_GetReadyState,
1094 media_engine_IsSeeking,
1095 media_engine_GetCurrentTime,
1096 media_engine_SetCurrentTime,
1097 media_engine_GetStartTime,
1098 media_engine_GetDuration,
1099 media_engine_IsPaused,
1100 media_engine_GetDefaultPlaybackRate,
1101 media_engine_SetDefaultPlaybackRate,
1102 media_engine_GetPlaybackRate,
1103 media_engine_SetPlaybackRate,
1104 media_engine_GetPlayed,
1105 media_engine_GetSeekable,
1106 media_engine_IsEnded,
1107 media_engine_GetAutoPlay,
1108 media_engine_SetAutoPlay,
1109 media_engine_GetLoop,
1110 media_engine_SetLoop,
1111 media_engine_Play,
1112 media_engine_Pause,
1113 media_engine_GetMuted,
1114 media_engine_SetMuted,
1115 media_engine_GetVolume,
1116 media_engine_SetVolume,
1117 media_engine_HasVideo,
1118 media_engine_HasAudio,
1119 media_engine_GetNativeVideoSize,
1120 media_engine_GetVideoAspectRatio,
1121 media_engine_Shutdown,
1122 media_engine_TransferVideoFrame,
1123 media_engine_OnVideoStreamTick,
1126 static HRESULT WINAPI media_engine_factory_QueryInterface(IMFMediaEngineClassFactory *iface, REFIID riid, void **obj)
1128 if (IsEqualIID(riid, &IID_IMFMediaEngineClassFactory) ||
1129 IsEqualIID(riid, &IID_IUnknown))
1131 *obj = iface;
1132 IMFMediaEngineClassFactory_AddRef(iface);
1133 return S_OK;
1136 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1137 *obj = NULL;
1138 return E_NOINTERFACE;
1141 static ULONG WINAPI media_engine_factory_AddRef(IMFMediaEngineClassFactory *iface)
1143 return 2;
1146 static ULONG WINAPI media_engine_factory_Release(IMFMediaEngineClassFactory *iface)
1148 return 1;
1151 static HRESULT init_media_engine(DWORD flags, IMFAttributes *attributes, struct media_engine *engine)
1153 DXGI_FORMAT output_format;
1154 UINT64 playback_hwnd;
1155 HRESULT hr;
1157 engine->IMFMediaEngine_iface.lpVtbl = &media_engine_vtbl;
1158 engine->session_events.lpVtbl = &media_engine_session_events_vtbl;
1159 engine->load_handler.lpVtbl = &media_engine_load_handler_vtbl;
1160 engine->refcount = 1;
1161 engine->flags = (flags & MF_MEDIA_ENGINE_CREATEFLAGS_MASK) | FLAGS_ENGINE_PAUSED;
1162 engine->default_playback_rate = 1.0;
1163 engine->playback_rate = 1.0;
1164 engine->volume = 1.0;
1165 engine->duration = NAN;
1166 InitializeCriticalSection(&engine->cs);
1168 hr = IMFAttributes_GetUnknown(attributes, &MF_MEDIA_ENGINE_CALLBACK, &IID_IMFMediaEngineNotify,
1169 (void **)&engine->callback);
1170 if (FAILED(hr))
1171 return hr;
1173 if (FAILED(hr = MFCreateMediaSession(NULL, &engine->session)))
1174 return hr;
1176 if (FAILED(hr = IMFMediaSession_BeginGetEvent(engine->session, &engine->session_events, NULL)))
1177 return hr;
1179 if (FAILED(hr = MFCreateSourceResolver(&engine->resolver)))
1180 return hr;
1182 if (FAILED(hr = MFCreateAttributes(&engine->attributes, 0)))
1183 return hr;
1185 if (FAILED(hr = IMFAttributes_CopyAllItems(attributes, engine->attributes)))
1186 return hr;
1188 IMFAttributes_GetUINT64(attributes, &MF_MEDIA_ENGINE_PLAYBACK_HWND, &playback_hwnd);
1189 hr = IMFAttributes_GetUINT32(attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, &output_format);
1190 if (playback_hwnd) /* FIXME: handle MF_MEDIA_ENGINE_PLAYBACK_VISUAL */
1191 engine->mode = MEDIA_ENGINE_RENDERING_MODE;
1192 else
1194 if (SUCCEEDED(hr))
1195 engine->mode = MEDIA_ENGINE_FRAME_SERVER_MODE;
1196 else
1197 engine->mode = MEDIA_ENGINE_AUDIO_MODE;
1200 return S_OK;
1203 static HRESULT WINAPI media_engine_factory_CreateInstance(IMFMediaEngineClassFactory *iface, DWORD flags,
1204 IMFAttributes *attributes, IMFMediaEngine **engine)
1206 struct media_engine *object;
1207 HRESULT hr;
1209 TRACE("%p, %#x, %p, %p.\n", iface, flags, attributes, engine);
1211 if (!attributes || !engine)
1212 return E_POINTER;
1214 object = heap_alloc_zero(sizeof(*object));
1215 if (!object)
1216 return E_OUTOFMEMORY;
1218 hr = init_media_engine(flags, attributes, object);
1219 if (FAILED(hr))
1221 free_media_engine(object);
1222 return hr;
1225 *engine = &object->IMFMediaEngine_iface;
1227 return S_OK;
1230 static HRESULT WINAPI media_engine_factory_CreateTimeRange(IMFMediaEngineClassFactory *iface,
1231 IMFMediaTimeRange **range)
1233 FIXME("(%p, %p): stub.\n", iface, range);
1235 return E_NOTIMPL;
1238 static HRESULT WINAPI media_engine_factory_CreateError(IMFMediaEngineClassFactory *iface, IMFMediaError **error)
1240 TRACE("%p, %p.\n", iface, error);
1242 return create_media_error(error);
1245 static const IMFMediaEngineClassFactoryVtbl media_engine_factory_vtbl =
1247 media_engine_factory_QueryInterface,
1248 media_engine_factory_AddRef,
1249 media_engine_factory_Release,
1250 media_engine_factory_CreateInstance,
1251 media_engine_factory_CreateTimeRange,
1252 media_engine_factory_CreateError,
1255 static IMFMediaEngineClassFactory media_engine_factory = { &media_engine_factory_vtbl };
1257 static HRESULT WINAPI classfactory_QueryInterface(IClassFactory *iface, REFIID riid, void **obj)
1259 TRACE("(%s, %p).\n", debugstr_guid(riid), obj);
1261 if (IsEqualGUID(riid, &IID_IClassFactory) ||
1262 IsEqualGUID(riid, &IID_IUnknown))
1264 IClassFactory_AddRef(iface);
1265 *obj = iface;
1266 return S_OK;
1269 WARN("interface %s not implemented.\n", debugstr_guid(riid));
1270 *obj = NULL;
1271 return E_NOINTERFACE;
1274 static ULONG WINAPI classfactory_AddRef(IClassFactory *iface)
1276 return 2;
1279 static ULONG WINAPI classfactory_Release(IClassFactory *iface)
1281 return 1;
1284 static HRESULT WINAPI classfactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **obj)
1286 TRACE("(%p, %s, %p).\n", outer, debugstr_guid(riid), obj);
1288 *obj = NULL;
1290 if (outer)
1291 return CLASS_E_NOAGGREGATION;
1293 return IMFMediaEngineClassFactory_QueryInterface(&media_engine_factory, riid, obj);
1296 static HRESULT WINAPI classfactory_LockServer(IClassFactory *iface, BOOL dolock)
1298 FIXME("(%d): stub.\n", dolock);
1299 return S_OK;
1302 static const struct IClassFactoryVtbl class_factory_vtbl =
1304 classfactory_QueryInterface,
1305 classfactory_AddRef,
1306 classfactory_Release,
1307 classfactory_CreateInstance,
1308 classfactory_LockServer,
1311 static IClassFactory classfactory = { &class_factory_vtbl };
1313 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **obj)
1315 TRACE("(%s, %s, %p).\n", debugstr_guid(clsid), debugstr_guid(riid), obj);
1317 if (IsEqualGUID(clsid, &CLSID_MFMediaEngineClassFactory))
1318 return IClassFactory_QueryInterface(&classfactory, riid, obj);
1320 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
1321 *obj = NULL;
1322 return CLASS_E_CLASSNOTAVAILABLE;
1325 HRESULT WINAPI DllCanUnloadNow(void)
1327 return S_FALSE;