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
28 #include "mfmediaengine.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
)
41 case DLL_WINE_PREATTACH
:
42 return FALSE
; /* prefer native version */
43 case DLL_PROCESS_ATTACH
:
44 DisableThreadLibraryCalls(instance
);
51 enum media_engine_mode
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,
75 IMFMediaEngine IMFMediaEngine_iface
;
76 IMFAsyncCallback session_events
;
77 IMFAsyncCallback load_handler
;
79 IMFMediaEngineNotify
*callback
;
80 IMFAttributes
*attributes
;
81 enum media_engine_mode mode
;
84 double default_playback_rate
;
87 MF_MEDIA_ENGINE_ERR error_code
;
88 HRESULT extended_code
;
89 IMFMediaSession
*session
;
90 IMFSourceResolver
*resolver
;
97 IMFMediaError IMFMediaError_iface
;
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
))
116 IMFMediaError_AddRef(iface
);
120 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
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
);
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
);
148 static USHORT WINAPI
media_error_GetErrorCode(IMFMediaError
*iface
)
150 struct media_error
*me
= impl_from_IMFMediaError(iface
);
151 TRACE("%p.\n", iface
);
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
)
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
;
187 static const IMFMediaErrorVtbl media_error_vtbl
=
189 media_error_QueryInterface
,
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
;
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
;
215 static void media_engine_set_flag(struct media_engine
*engine
, unsigned int mask
, BOOL value
)
218 engine
->flags
|= mask
;
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
))
244 IMFAsyncCallback_AddRef(iface
);
248 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
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
)
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
;
277 if (FAILED(hr
= IMFMediaSession_EndGetEvent(engine
->session
, result
, &event
)))
279 WARN("Failed to get session event, hr %#x.\n", hr
);
283 if (FAILED(hr
= IMFMediaEvent_GetType(event
, &event_type
)))
285 WARN("Failed to get event type, hr %#x.\n", hr
);
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);
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
);
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
;
339 if (FAILED(hr
= IMFMediaSource_CreatePresentationDescriptor(source
, &pd
)))
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
;
353 IMFPresentationDescriptor_DeselectStream(pd
, i
);
355 if (sd_audio
&& sd_video
)
358 IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd
, i
, &selected
, &sd
);
360 if (SUCCEEDED(IMFStreamDescriptor_GetMediaTypeHandler(sd
, &type_handler
)))
364 IMFMediaTypeHandler_GetMajorType(type_handler
, &major
);
366 if (IsEqualGUID(&major
, &MFMediaType_Audio
) && !sd_audio
)
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
))
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
);
390 engine
->flags
|= FLAGS_ENGINE_HAS_VIDEO
;
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;
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 */
410 IMFStreamDescriptor_Release(sd_video
);
412 IMFStreamDescriptor_Release(sd_audio
);
414 IMFPresentationDescriptor_Release(pd
);
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
;
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
);
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
);
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
);
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
))
474 IMFMediaEngine_AddRef(iface
);
478 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
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
);
493 static void free_media_engine(struct media_engine
*engine
)
495 if (engine
->callback
)
496 IMFMediaEngineNotify_Release(engine
->callback
);
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
);
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
);
516 free_media_engine(engine
);
521 static HRESULT WINAPI
media_engine_GetError(IMFMediaEngine
*iface
, IMFMediaError
**error
)
523 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
526 TRACE("%p, %p.\n", iface
, error
);
530 EnterCriticalSection(&engine
->cs
);
531 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
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
);
546 static HRESULT WINAPI
media_engine_SetErrorCode(IMFMediaEngine
*iface
, MF_MEDIA_ENGINE_ERR code
)
548 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
551 TRACE("%p, %u.\n", iface
, code
);
553 if ((unsigned int)code
> MF_MEDIA_ENGINE_ERR_ENCRYPTED
)
556 EnterCriticalSection(&engine
->cs
);
557 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
560 engine
->error_code
= code
;
561 LeaveCriticalSection(&engine
->cs
);
566 static HRESULT WINAPI
media_engine_SetSourceElements(IMFMediaEngine
*iface
, IMFMediaEngineSrcElements
*elements
)
568 FIXME("(%p, %p): stub.\n", iface
, elements
);
573 static HRESULT WINAPI
media_engine_SetSource(IMFMediaEngine
*iface
, BSTR url
)
575 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
578 TRACE("%p, %s.\n", iface
, debugstr_w(url
));
580 EnterCriticalSection(&engine
->cs
);
582 SysFreeString(engine
->current_source
);
583 engine
->current_source
= NULL
;
585 engine
->current_source
= SysAllocString(url
);
587 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS
, 0, 0);
591 IPropertyStore
*props
= NULL
;
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
);
602 IPropertyStore_Release(props
);
605 LeaveCriticalSection(&engine
->cs
);
610 static HRESULT WINAPI
media_engine_GetCurrentSource(IMFMediaEngine
*iface
, BSTR
*url
)
612 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
615 TRACE("%p, %p.\n", iface
, url
);
619 EnterCriticalSection(&engine
->cs
);
620 if (engine
->current_source
)
622 if (!(*url
= SysAllocString(engine
->current_source
)))
625 LeaveCriticalSection(&engine
->cs
);
630 static USHORT WINAPI
media_engine_GetNetworkState(IMFMediaEngine
*iface
)
632 FIXME("(%p): stub.\n", iface
);
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
);
651 static HRESULT WINAPI
media_engine_GetBuffered(IMFMediaEngine
*iface
, IMFMediaTimeRange
**buffered
)
653 FIXME("(%p, %p): stub.\n", iface
, buffered
);
658 static HRESULT WINAPI
media_engine_Load(IMFMediaEngine
*iface
)
660 FIXME("(%p): stub.\n", iface
);
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
);
672 static USHORT WINAPI
media_engine_GetReadyState(IMFMediaEngine
*iface
)
674 FIXME("(%p): stub.\n", iface
);
679 static BOOL WINAPI
media_engine_IsSeeking(IMFMediaEngine
*iface
)
681 FIXME("(%p): stub.\n", iface
);
686 static double WINAPI
media_engine_GetCurrentTime(IMFMediaEngine
*iface
)
688 FIXME("(%p): stub.\n", iface
);
693 static HRESULT WINAPI
media_engine_SetCurrentTime(IMFMediaEngine
*iface
, double time
)
695 FIXME("(%p, %f): stub.\n", iface
, time
);
700 static double WINAPI
media_engine_GetStartTime(IMFMediaEngine
*iface
)
702 FIXME("(%p): stub.\n", iface
);
707 static double WINAPI
media_engine_GetDuration(IMFMediaEngine
*iface
)
709 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
712 TRACE("%p.\n", iface
);
714 EnterCriticalSection(&engine
->cs
);
715 value
= engine
->duration
;
716 LeaveCriticalSection(&engine
->cs
);
721 static BOOL WINAPI
media_engine_IsPaused(IMFMediaEngine
*iface
)
723 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
726 TRACE("%p.\n", iface
);
728 EnterCriticalSection(&engine
->cs
);
729 value
= !!(engine
->flags
& FLAGS_ENGINE_PAUSED
);
730 LeaveCriticalSection(&engine
->cs
);
735 static double WINAPI
media_engine_GetDefaultPlaybackRate(IMFMediaEngine
*iface
)
737 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
740 TRACE("%p.\n", iface
);
742 EnterCriticalSection(&engine
->cs
);
743 rate
= engine
->default_playback_rate
;
744 LeaveCriticalSection(&engine
->cs
);
749 static HRESULT WINAPI
media_engine_SetDefaultPlaybackRate(IMFMediaEngine
*iface
, double rate
)
751 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
754 TRACE("%p, %f.\n", iface
, rate
);
756 EnterCriticalSection(&engine
->cs
);
757 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
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
);
769 static double WINAPI
media_engine_GetPlaybackRate(IMFMediaEngine
*iface
)
771 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
774 TRACE("%p.\n", iface
);
776 EnterCriticalSection(&engine
->cs
);
777 rate
= engine
->playback_rate
;
778 LeaveCriticalSection(&engine
->cs
);
783 static HRESULT WINAPI
media_engine_SetPlaybackRate(IMFMediaEngine
*iface
, double rate
)
785 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
788 TRACE("%p, %f.\n", iface
, rate
);
790 EnterCriticalSection(&engine
->cs
);
791 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
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
);
803 static HRESULT WINAPI
media_engine_GetPlayed(IMFMediaEngine
*iface
, IMFMediaTimeRange
**played
)
805 FIXME("(%p, %p): stub.\n", iface
, played
);
810 static HRESULT WINAPI
media_engine_GetSeekable(IMFMediaEngine
*iface
, IMFMediaTimeRange
**seekable
)
812 FIXME("(%p, %p): stub.\n", iface
, seekable
);
817 static BOOL WINAPI
media_engine_IsEnded(IMFMediaEngine
*iface
)
819 FIXME("(%p): stub.\n", iface
);
824 static BOOL WINAPI
media_engine_GetAutoPlay(IMFMediaEngine
*iface
)
826 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
829 TRACE("%p.\n", iface
);
831 EnterCriticalSection(&engine
->cs
);
832 value
= !!(engine
->flags
& FLAGS_ENGINE_AUTO_PLAY
);
833 LeaveCriticalSection(&engine
->cs
);
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
);
851 static BOOL WINAPI
media_engine_GetLoop(IMFMediaEngine
*iface
)
853 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
856 TRACE("%p.\n", iface
);
858 EnterCriticalSection(&engine
->cs
);
859 value
= !!(engine
->flags
& FLAGS_ENGINE_LOOP
);
860 LeaveCriticalSection(&engine
->cs
);
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
);
878 static HRESULT WINAPI
media_engine_Play(IMFMediaEngine
*iface
)
880 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
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);
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
);
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
);
931 static BOOL WINAPI
media_engine_GetMuted(IMFMediaEngine
*iface
)
933 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
936 TRACE("%p.\n", iface
);
938 EnterCriticalSection(&engine
->cs
);
939 ret
= !!(engine
->flags
& FLAGS_ENGINE_MUTED
);
940 LeaveCriticalSection(&engine
->cs
);
945 static HRESULT WINAPI
media_engine_SetMuted(IMFMediaEngine
*iface
, BOOL muted
)
947 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
950 TRACE("%p, %d.\n", iface
, muted
);
952 EnterCriticalSection(&engine
->cs
);
953 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
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
);
965 static double WINAPI
media_engine_GetVolume(IMFMediaEngine
*iface
)
967 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
970 TRACE("%p.\n", iface
);
972 EnterCriticalSection(&engine
->cs
);
973 volume
= engine
->volume
;
974 LeaveCriticalSection(&engine
->cs
);
979 static HRESULT WINAPI
media_engine_SetVolume(IMFMediaEngine
*iface
, double volume
)
981 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
984 TRACE("%p, %f.\n", iface
, volume
);
986 EnterCriticalSection(&engine
->cs
);
987 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
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
);
999 static BOOL WINAPI
media_engine_HasVideo(IMFMediaEngine
*iface
)
1001 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1004 TRACE("%p.\n", iface
);
1006 EnterCriticalSection(&engine
->cs
);
1007 value
= !!(engine
->flags
& FLAGS_ENGINE_HAS_VIDEO
);
1008 LeaveCriticalSection(&engine
->cs
);
1013 static BOOL WINAPI
media_engine_HasAudio(IMFMediaEngine
*iface
)
1015 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1018 TRACE("%p.\n", iface
);
1020 EnterCriticalSection(&engine
->cs
);
1021 value
= !!(engine
->flags
& FLAGS_ENGINE_HAS_AUDIO
);
1022 LeaveCriticalSection(&engine
->cs
);
1027 static HRESULT WINAPI
media_engine_GetNativeVideoSize(IMFMediaEngine
*iface
, DWORD
*cx
, DWORD
*cy
)
1029 FIXME("(%p, %p, %p): stub.\n", iface
, cx
, cy
);
1034 static HRESULT WINAPI
media_engine_GetVideoAspectRatio(IMFMediaEngine
*iface
, DWORD
*cx
, DWORD
*cy
)
1036 FIXME("(%p, %p, %p): stub.\n", iface
, cx
, cy
);
1041 static HRESULT WINAPI
media_engine_Shutdown(IMFMediaEngine
*iface
)
1043 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1046 FIXME("(%p): stub.\n", iface
);
1048 EnterCriticalSection(&engine
->cs
);
1049 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1053 engine
->flags
|= FLAGS_ENGINE_SHUT_DOWN
;
1054 IMFMediaSession_Shutdown(engine
->session
);
1056 LeaveCriticalSection(&engine
->cs
);
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
);
1070 static HRESULT WINAPI
media_engine_OnVideoStreamTick(IMFMediaEngine
*iface
, LONGLONG
*time
)
1072 FIXME("(%p, %p): stub.\n", iface
, time
);
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
,
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
,
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
))
1132 IMFMediaEngineClassFactory_AddRef(iface
);
1136 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
1138 return E_NOINTERFACE
;
1141 static ULONG WINAPI
media_engine_factory_AddRef(IMFMediaEngineClassFactory
*iface
)
1146 static ULONG WINAPI
media_engine_factory_Release(IMFMediaEngineClassFactory
*iface
)
1151 static HRESULT
init_media_engine(DWORD flags
, IMFAttributes
*attributes
, struct media_engine
*engine
)
1153 DXGI_FORMAT output_format
;
1154 UINT64 playback_hwnd
;
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
);
1173 if (FAILED(hr
= MFCreateMediaSession(NULL
, &engine
->session
)))
1176 if (FAILED(hr
= IMFMediaSession_BeginGetEvent(engine
->session
, &engine
->session_events
, NULL
)))
1179 if (FAILED(hr
= MFCreateSourceResolver(&engine
->resolver
)))
1182 if (FAILED(hr
= MFCreateAttributes(&engine
->attributes
, 0)))
1185 if (FAILED(hr
= IMFAttributes_CopyAllItems(attributes
, engine
->attributes
)))
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
;
1195 engine
->mode
= MEDIA_ENGINE_FRAME_SERVER_MODE
;
1197 engine
->mode
= MEDIA_ENGINE_AUDIO_MODE
;
1203 static HRESULT WINAPI
media_engine_factory_CreateInstance(IMFMediaEngineClassFactory
*iface
, DWORD flags
,
1204 IMFAttributes
*attributes
, IMFMediaEngine
**engine
)
1206 struct media_engine
*object
;
1209 TRACE("%p, %#x, %p, %p.\n", iface
, flags
, attributes
, engine
);
1211 if (!attributes
|| !engine
)
1214 object
= heap_alloc_zero(sizeof(*object
));
1216 return E_OUTOFMEMORY
;
1218 hr
= init_media_engine(flags
, attributes
, object
);
1221 free_media_engine(object
);
1225 *engine
= &object
->IMFMediaEngine_iface
;
1230 static HRESULT WINAPI
media_engine_factory_CreateTimeRange(IMFMediaEngineClassFactory
*iface
,
1231 IMFMediaTimeRange
**range
)
1233 FIXME("(%p, %p): stub.\n", iface
, range
);
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
);
1269 WARN("interface %s not implemented.\n", debugstr_guid(riid
));
1271 return E_NOINTERFACE
;
1274 static ULONG WINAPI
classfactory_AddRef(IClassFactory
*iface
)
1279 static ULONG WINAPI
classfactory_Release(IClassFactory
*iface
)
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
);
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
);
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
));
1322 return CLASS_E_CLASSNOTAVAILABLE
;
1325 HRESULT WINAPI
DllCanUnloadNow(void)