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"
34 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
36 static BOOL
mf_array_reserve(void **elements
, size_t *capacity
, size_t count
, size_t size
)
38 size_t new_capacity
, max_capacity
;
41 if (count
<= *capacity
)
44 max_capacity
= ~(SIZE_T
)0 / size
;
45 if (count
> max_capacity
)
48 new_capacity
= max(4, *capacity
);
49 while (new_capacity
< count
&& new_capacity
<= max_capacity
/ 2)
51 if (new_capacity
< count
)
52 new_capacity
= max_capacity
;
54 if (!(new_elements
= realloc(*elements
, new_capacity
* size
)))
57 *elements
= new_elements
;
58 *capacity
= new_capacity
;
63 enum media_engine_mode
66 MEDIA_ENGINE_AUDIO_MODE
,
67 MEDIA_ENGINE_RENDERING_MODE
,
68 MEDIA_ENGINE_FRAME_SERVER_MODE
,
71 /* Used with create flags. */
72 enum media_engine_flags
74 /* MF_MEDIA_ENGINE_CREATEFLAGS_MASK is 0x1f. */
75 FLAGS_ENGINE_SHUT_DOWN
= 0x20,
76 FLAGS_ENGINE_AUTO_PLAY
= 0x40,
77 FLAGS_ENGINE_LOOP
= 0x80,
78 FLAGS_ENGINE_PAUSED
= 0x100,
79 FLAGS_ENGINE_WAITING
= 0x200,
80 FLAGS_ENGINE_MUTED
= 0x400,
81 FLAGS_ENGINE_HAS_AUDIO
= 0x800,
82 FLAGS_ENGINE_HAS_VIDEO
= 0x1000,
83 FLAGS_ENGINE_FIRST_FRAME
= 0x2000,
84 FLAGS_ENGINE_IS_ENDED
= 0x4000,
97 IMFMediaEngine IMFMediaEngine_iface
;
98 IMFAsyncCallback session_events
;
99 IMFAsyncCallback load_handler
;
100 IMFSampleGrabberSinkCallback grabber_callback
;
102 IMFMediaEngineNotify
*callback
;
103 IMFAttributes
*attributes
;
104 enum media_engine_mode mode
;
106 double playback_rate
;
107 double default_playback_rate
;
110 MF_MEDIA_ENGINE_ERR error_code
;
111 HRESULT extended_code
;
112 MF_MEDIA_ENGINE_READY ready_state
;
113 MF_MEDIA_ENGINE_PRELOAD preload
;
114 IMFMediaSession
*session
;
115 IMFPresentationClock
*clock
;
116 IMFSourceResolver
*resolver
;
118 struct video_frame video_frame
;
130 IMFMediaTimeRange IMFMediaTimeRange_iface
;
133 struct range
*ranges
;
138 static struct time_range
*impl_from_IMFMediaTimeRange(IMFMediaTimeRange
*iface
)
140 return CONTAINING_RECORD(iface
, struct time_range
, IMFMediaTimeRange_iface
);
145 IMFMediaError IMFMediaError_iface
;
148 HRESULT extended_code
;
151 static struct media_error
*impl_from_IMFMediaError(IMFMediaError
*iface
)
153 return CONTAINING_RECORD(iface
, struct media_error
, IMFMediaError_iface
);
156 static HRESULT WINAPI
media_error_QueryInterface(IMFMediaError
*iface
, REFIID riid
, void **obj
)
158 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
160 if (IsEqualIID(riid
, &IID_IMFMediaError
) ||
161 IsEqualIID(riid
, &IID_IUnknown
))
164 IMFMediaError_AddRef(iface
);
168 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
170 return E_NOINTERFACE
;
173 static ULONG WINAPI
media_error_AddRef(IMFMediaError
*iface
)
175 struct media_error
*me
= impl_from_IMFMediaError(iface
);
176 ULONG refcount
= InterlockedIncrement(&me
->refcount
);
178 TRACE("%p, refcount %u.\n", iface
, refcount
);
183 static ULONG WINAPI
media_error_Release(IMFMediaError
*iface
)
185 struct media_error
*me
= impl_from_IMFMediaError(iface
);
186 ULONG refcount
= InterlockedDecrement(&me
->refcount
);
188 TRACE("%p, refcount %u.\n", iface
, refcount
);
196 static USHORT WINAPI
media_error_GetErrorCode(IMFMediaError
*iface
)
198 struct media_error
*me
= impl_from_IMFMediaError(iface
);
199 TRACE("%p.\n", iface
);
203 static HRESULT WINAPI
media_error_GetExtendedErrorCode(IMFMediaError
*iface
)
205 struct media_error
*me
= impl_from_IMFMediaError(iface
);
206 TRACE("%p.\n", iface
);
207 return me
->extended_code
;
210 static HRESULT WINAPI
media_error_SetErrorCode(IMFMediaError
*iface
, MF_MEDIA_ENGINE_ERR code
)
212 struct media_error
*me
= impl_from_IMFMediaError(iface
);
214 TRACE("%p, %u.\n", iface
, code
);
216 if ((unsigned int)code
> MF_MEDIA_ENGINE_ERR_ENCRYPTED
)
224 static HRESULT WINAPI
media_error_SetExtendedErrorCode(IMFMediaError
*iface
, HRESULT code
)
226 struct media_error
*me
= impl_from_IMFMediaError(iface
);
228 TRACE("%p, %#x.\n", iface
, code
);
230 me
->extended_code
= code
;
235 static const IMFMediaErrorVtbl media_error_vtbl
=
237 media_error_QueryInterface
,
240 media_error_GetErrorCode
,
241 media_error_GetExtendedErrorCode
,
242 media_error_SetErrorCode
,
243 media_error_SetExtendedErrorCode
,
246 static HRESULT
create_media_error(IMFMediaError
**ret
)
248 struct media_error
*object
;
252 if (!(object
= calloc(1, sizeof(*object
))))
253 return E_OUTOFMEMORY
;
255 object
->IMFMediaError_iface
.lpVtbl
= &media_error_vtbl
;
256 object
->refcount
= 1;
258 *ret
= &object
->IMFMediaError_iface
;
263 static HRESULT WINAPI
time_range_QueryInterface(IMFMediaTimeRange
*iface
, REFIID riid
, void **obj
)
265 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
267 if (IsEqualIID(riid
, &IID_IMFMediaTimeRange
) ||
268 IsEqualIID(riid
, &IID_IUnknown
))
271 IMFMediaTimeRange_AddRef(iface
);
275 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
277 return E_NOINTERFACE
;
280 static ULONG WINAPI
time_range_AddRef(IMFMediaTimeRange
*iface
)
282 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
283 ULONG refcount
= InterlockedIncrement(&range
->refcount
);
285 TRACE("%p, refcount %u.\n", iface
, refcount
);
290 static ULONG WINAPI
time_range_Release(IMFMediaTimeRange
*iface
)
292 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
293 ULONG refcount
= InterlockedDecrement(&range
->refcount
);
295 TRACE("%p, refcount %u.\n", iface
, refcount
);
306 static DWORD WINAPI
time_range_GetLength(IMFMediaTimeRange
*iface
)
308 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
310 TRACE("%p.\n", iface
);
315 static HRESULT WINAPI
time_range_GetStart(IMFMediaTimeRange
*iface
, DWORD idx
, double *start
)
317 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
319 TRACE("%p, %u, %p.\n", iface
, idx
, start
);
321 if (idx
>= range
->count
)
324 *start
= range
->ranges
[idx
].start
;
329 static HRESULT WINAPI
time_range_GetEnd(IMFMediaTimeRange
*iface
, DWORD idx
, double *end
)
331 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
333 TRACE("%p, %u, %p.\n", iface
, idx
, end
);
335 if (idx
>= range
->count
)
338 *end
= range
->ranges
[idx
].end
;
343 static BOOL WINAPI
time_range_ContainsTime(IMFMediaTimeRange
*iface
, double time
)
345 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
348 TRACE("%p, %.8e.\n", iface
, time
);
350 for (i
= 0; i
< range
->count
; ++i
)
352 if (time
>= range
->ranges
[i
].start
&& time
<= range
->ranges
[i
].end
)
359 static HRESULT WINAPI
time_range_AddRange(IMFMediaTimeRange
*iface
, double start
, double end
)
361 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
363 TRACE("%p, %.8e, %.8e.\n", iface
, start
, end
);
367 FIXME("Range merging is not implemented.\n");
371 if (!mf_array_reserve((void **)&range
->ranges
, &range
->capacity
, range
->count
+ 1, sizeof(*range
->ranges
)))
372 return E_OUTOFMEMORY
;
374 range
->ranges
[range
->count
].start
= start
;
375 range
->ranges
[range
->count
].end
= end
;
381 static HRESULT WINAPI
time_range_Clear(IMFMediaTimeRange
*iface
)
383 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
385 TRACE("%p.\n", iface
);
392 static const IMFMediaTimeRangeVtbl time_range_vtbl
=
394 time_range_QueryInterface
,
397 time_range_GetLength
,
400 time_range_ContainsTime
,
405 static HRESULT
create_time_range(IMFMediaTimeRange
**range
)
407 struct time_range
*object
;
409 object
= calloc(1, sizeof(*object
));
411 return E_OUTOFMEMORY
;
413 object
->IMFMediaTimeRange_iface
.lpVtbl
= &time_range_vtbl
;
414 object
->refcount
= 1;
416 *range
= &object
->IMFMediaTimeRange_iface
;
421 static void media_engine_set_flag(struct media_engine
*engine
, unsigned int mask
, BOOL value
)
424 engine
->flags
|= mask
;
426 engine
->flags
&= ~mask
;
429 static inline struct media_engine
*impl_from_IMFMediaEngine(IMFMediaEngine
*iface
)
431 return CONTAINING_RECORD(iface
, struct media_engine
, IMFMediaEngine_iface
);
434 static struct media_engine
*impl_from_session_events_IMFAsyncCallback(IMFAsyncCallback
*iface
)
436 return CONTAINING_RECORD(iface
, struct media_engine
, session_events
);
439 static struct media_engine
*impl_from_load_handler_IMFAsyncCallback(IMFAsyncCallback
*iface
)
441 return CONTAINING_RECORD(iface
, struct media_engine
, load_handler
);
444 static struct media_engine
*impl_from_IMFSampleGrabberSinkCallback(IMFSampleGrabberSinkCallback
*iface
)
446 return CONTAINING_RECORD(iface
, struct media_engine
, grabber_callback
);
449 static unsigned int get_gcd(unsigned int a
, unsigned int b
)
463 static void media_engine_get_frame_size(struct media_engine
*engine
, IMFTopology
*topology
)
465 IMFMediaTypeHandler
*handler
;
466 IMFMediaType
*media_type
;
467 IMFStreamDescriptor
*sd
;
468 IMFTopologyNode
*node
;
473 engine
->video_frame
.size
.cx
= 0;
474 engine
->video_frame
.size
.cy
= 0;
475 engine
->video_frame
.ratio
.cx
= 1;
476 engine
->video_frame
.ratio
.cy
= 1;
478 if (FAILED(IMFTopology_GetNodeByID(topology
, engine
->video_frame
.node_id
, &node
)))
481 hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_STREAM_DESCRIPTOR
,
482 &IID_IMFStreamDescriptor
, (void **)&sd
);
483 IMFTopologyNode_Release(node
);
487 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
488 IMFStreamDescriptor_Release(sd
);
492 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, &media_type
);
493 IMFMediaTypeHandler_Release(handler
);
496 WARN("Failed to get current media type %#x.\n", hr
);
500 IMFMediaType_GetUINT64(media_type
, &MF_MT_FRAME_SIZE
, &size
);
502 engine
->video_frame
.size
.cx
= size
>> 32;
503 engine
->video_frame
.size
.cy
= size
;
505 if ((gcd
= get_gcd(engine
->video_frame
.size
.cx
, engine
->video_frame
.size
.cy
)))
507 engine
->video_frame
.ratio
.cx
= engine
->video_frame
.size
.cx
/ gcd
;
508 engine
->video_frame
.ratio
.cy
= engine
->video_frame
.size
.cy
/ gcd
;
511 IMFMediaType_Release(media_type
);
514 static HRESULT WINAPI
media_engine_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
516 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
517 IsEqualIID(riid
, &IID_IUnknown
))
520 IMFAsyncCallback_AddRef(iface
);
524 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
526 return E_NOINTERFACE
;
529 static ULONG WINAPI
media_engine_session_events_AddRef(IMFAsyncCallback
*iface
)
531 struct media_engine
*engine
= impl_from_session_events_IMFAsyncCallback(iface
);
532 return IMFMediaEngine_AddRef(&engine
->IMFMediaEngine_iface
);
535 static ULONG WINAPI
media_engine_session_events_Release(IMFAsyncCallback
*iface
)
537 struct media_engine
*engine
= impl_from_session_events_IMFAsyncCallback(iface
);
538 return IMFMediaEngine_Release(&engine
->IMFMediaEngine_iface
);
541 static HRESULT WINAPI
media_engine_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
546 static HRESULT WINAPI
media_engine_session_events_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
548 struct media_engine
*engine
= impl_from_session_events_IMFAsyncCallback(iface
);
549 IMFMediaEvent
*event
= NULL
;
550 MediaEventType event_type
;
553 if (FAILED(hr
= IMFMediaSession_EndGetEvent(engine
->session
, result
, &event
)))
555 WARN("Failed to get session event, hr %#x.\n", hr
);
559 if (FAILED(hr
= IMFMediaEvent_GetType(event
, &event_type
)))
561 WARN("Failed to get event type, hr %#x.\n", hr
);
567 case MEBufferingStarted
:
568 case MEBufferingStopped
:
570 IMFMediaEngineNotify_EventNotify(engine
->callback
, event_type
== MEBufferingStarted
?
571 MF_MEDIA_ENGINE_EVENT_BUFFERINGSTARTED
: MF_MEDIA_ENGINE_EVENT_BUFFERINGENDED
, 0, 0);
573 case MESessionTopologyStatus
:
575 UINT32 topo_status
= 0;
576 IMFTopology
*topology
;
579 IMFMediaEvent_GetUINT32(event
, &MF_EVENT_TOPOLOGY_STATUS
, &topo_status
);
580 if (topo_status
!= MF_TOPOSTATUS_READY
)
584 if (FAILED(IMFMediaEvent_GetValue(event
, &value
)))
587 if (value
.vt
!= VT_UNKNOWN
)
589 PropVariantClear(&value
);
593 topology
= (IMFTopology
*)value
.punkVal
;
595 EnterCriticalSection(&engine
->cs
);
597 engine
->ready_state
= MF_MEDIA_ENGINE_READY_HAVE_METADATA
;
599 media_engine_get_frame_size(engine
, topology
);
601 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE
, 0, 0);
602 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA
, 0, 0);
604 engine
->ready_state
= MF_MEDIA_ENGINE_READY_HAVE_ENOUGH_DATA
;
606 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_LOADEDDATA
, 0, 0);
607 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_CANPLAY
, 0, 0);
609 LeaveCriticalSection(&engine
->cs
);
611 PropVariantClear(&value
);
615 case MESessionStarted
:
617 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PLAYING
, 0, 0);
621 EnterCriticalSection(&engine
->cs
);
622 media_engine_set_flag(engine
, FLAGS_ENGINE_FIRST_FRAME
, FALSE
);
623 media_engine_set_flag(engine
, FLAGS_ENGINE_IS_ENDED
, TRUE
);
624 engine
->video_frame
.pts
= MINLONGLONG
;
625 LeaveCriticalSection(&engine
->cs
);
627 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_ENDED
, 0, 0);
634 IMFMediaEvent_Release(event
);
636 if (FAILED(hr
= IMFMediaSession_BeginGetEvent(engine
->session
, iface
, NULL
)))
637 WARN("Failed to subscribe to session events, hr %#x.\n", hr
);
642 static const IMFAsyncCallbackVtbl media_engine_session_events_vtbl
=
644 media_engine_callback_QueryInterface
,
645 media_engine_session_events_AddRef
,
646 media_engine_session_events_Release
,
647 media_engine_callback_GetParameters
,
648 media_engine_session_events_Invoke
,
651 static ULONG WINAPI
media_engine_load_handler_AddRef(IMFAsyncCallback
*iface
)
653 struct media_engine
*engine
= impl_from_load_handler_IMFAsyncCallback(iface
);
654 return IMFMediaEngine_AddRef(&engine
->IMFMediaEngine_iface
);
657 static ULONG WINAPI
media_engine_load_handler_Release(IMFAsyncCallback
*iface
)
659 struct media_engine
*engine
= impl_from_load_handler_IMFAsyncCallback(iface
);
660 return IMFMediaEngine_Release(&engine
->IMFMediaEngine_iface
);
663 static HRESULT
media_engine_create_source_node(IMFMediaSource
*source
, IMFPresentationDescriptor
*pd
, IMFStreamDescriptor
*sd
,
664 IMFTopologyNode
**node
)
668 if (FAILED(hr
= MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE
, node
)))
671 IMFTopologyNode_SetUnknown(*node
, &MF_TOPONODE_SOURCE
, (IUnknown
*)source
);
672 IMFTopologyNode_SetUnknown(*node
, &MF_TOPONODE_PRESENTATION_DESCRIPTOR
, (IUnknown
*)pd
);
673 IMFTopologyNode_SetUnknown(*node
, &MF_TOPONODE_STREAM_DESCRIPTOR
, (IUnknown
*)sd
);
678 static HRESULT
media_engine_create_audio_renderer(struct media_engine
*engine
, IMFTopologyNode
**node
)
680 unsigned int category
, role
;
681 IMFActivate
*sar_activate
;
686 if (FAILED(hr
= MFCreateAudioRendererActivate(&sar_activate
)))
689 /* Configuration attributes keys differ between Engine and SAR. */
690 if (SUCCEEDED(IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_CATEGORY
, &category
)))
691 IMFActivate_SetUINT32(sar_activate
, &MF_AUDIO_RENDERER_ATTRIBUTE_STREAM_CATEGORY
, category
);
692 if (SUCCEEDED(IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE
, &role
)))
693 IMFActivate_SetUINT32(sar_activate
, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE
, role
);
695 if (SUCCEEDED(hr
= MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE
, node
)))
697 IMFTopologyNode_SetObject(*node
, (IUnknown
*)sar_activate
);
698 IMFTopologyNode_SetUINT32(*node
, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE
, FALSE
);
701 IMFActivate_Release(sar_activate
);
706 static HRESULT
media_engine_create_video_renderer(struct media_engine
*engine
, IMFTopologyNode
**node
)
708 DXGI_FORMAT output_format
;
709 IMFMediaType
*media_type
;
710 IMFActivate
*activate
;
716 if (FAILED(IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT
, &output_format
)))
718 WARN("Output format was not specified.\n");
722 memcpy(&subtype
, &MFVideoFormat_Base
, sizeof(subtype
));
723 if (!(subtype
.Data1
= MFMapDXGIFormatToDX9Format(output_format
)))
725 WARN("Unrecognized output format %#x.\n", output_format
);
729 if (FAILED(hr
= MFCreateMediaType(&media_type
)))
732 IMFMediaType_SetGUID(media_type
, &MF_MT_MAJOR_TYPE
, &MFMediaType_Video
);
733 IMFMediaType_SetGUID(media_type
, &MF_MT_SUBTYPE
, &subtype
);
735 hr
= MFCreateSampleGrabberSinkActivate(media_type
, &engine
->grabber_callback
, &activate
);
736 IMFMediaType_Release(media_type
);
740 if (SUCCEEDED(hr
= MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE
, node
)))
742 IMFTopologyNode_SetObject(*node
, (IUnknown
*)activate
);
743 IMFTopologyNode_SetUINT32(*node
, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE
, FALSE
);
746 IMFActivate_Release(activate
);
751 static HRESULT
media_engine_create_topology(struct media_engine
*engine
, IMFMediaSource
*source
)
753 IMFStreamDescriptor
*sd_audio
= NULL
, *sd_video
= NULL
;
754 unsigned int stream_count
= 0, i
;
755 IMFPresentationDescriptor
*pd
;
756 IMFTopology
*topology
;
760 memset(&engine
->video_frame
, 0, sizeof(engine
->video_frame
));
762 if (FAILED(hr
= IMFMediaSource_CreatePresentationDescriptor(source
, &pd
)))
765 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(pd
, &stream_count
)))
766 WARN("Failed to get stream count, hr %#x.\n", hr
);
768 /* Enable first video stream and first audio stream. */
770 for (i
= 0; i
< stream_count
; ++i
)
772 IMFMediaTypeHandler
*type_handler
;
773 IMFStreamDescriptor
*sd
;
776 IMFPresentationDescriptor_DeselectStream(pd
, i
);
778 if (sd_audio
&& sd_video
)
781 IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd
, i
, &selected
, &sd
);
783 if (SUCCEEDED(IMFStreamDescriptor_GetMediaTypeHandler(sd
, &type_handler
)))
787 IMFMediaTypeHandler_GetMajorType(type_handler
, &major
);
789 if (IsEqualGUID(&major
, &MFMediaType_Audio
) && !sd_audio
)
792 IMFStreamDescriptor_AddRef(sd_audio
);
793 IMFPresentationDescriptor_SelectStream(pd
, i
);
795 else if (IsEqualGUID(&major
, &MFMediaType_Video
) && !sd_video
&& !(engine
->flags
& MF_MEDIA_ENGINE_AUDIOONLY
))
798 IMFStreamDescriptor_AddRef(sd_video
);
799 IMFPresentationDescriptor_SelectStream(pd
, i
);
802 IMFMediaTypeHandler_Release(type_handler
);
806 if (!sd_video
&& !sd_audio
)
808 IMFPresentationDescriptor_Release(pd
);
812 media_engine_set_flag(engine
, FLAGS_ENGINE_HAS_VIDEO
, !!sd_video
);
813 media_engine_set_flag(engine
, FLAGS_ENGINE_HAS_AUDIO
, !!sd_audio
);
815 /* Assume live source if duration was not provided. */
816 if (SUCCEEDED(IMFPresentationDescriptor_GetUINT64(pd
, &MF_PD_DURATION
, &duration
)))
818 /* Convert 100ns to seconds. */
819 engine
->duration
= duration
/ 10000000;
822 engine
->duration
= INFINITY
;
824 if (SUCCEEDED(hr
= MFCreateTopology(&topology
)))
826 IMFTopologyNode
*sar_node
= NULL
, *audio_src
= NULL
;
827 IMFTopologyNode
*grabber_node
= NULL
, *video_src
= NULL
;
831 if (FAILED(hr
= media_engine_create_source_node(source
, pd
, sd_audio
, &audio_src
)))
832 WARN("Failed to create audio source node, hr %#x.\n", hr
);
834 if (FAILED(hr
= media_engine_create_audio_renderer(engine
, &sar_node
)))
835 WARN("Failed to create audio renderer node, hr %#x.\n", hr
);
837 if (sar_node
&& audio_src
)
839 IMFTopology_AddNode(topology
, audio_src
);
840 IMFTopology_AddNode(topology
, sar_node
);
841 IMFTopologyNode_ConnectOutput(audio_src
, 0, sar_node
, 0);
845 IMFTopologyNode_Release(sar_node
);
847 IMFTopologyNode_Release(audio_src
);
850 if (SUCCEEDED(hr
) && sd_video
)
852 if (FAILED(hr
= media_engine_create_source_node(source
, pd
, sd_video
, &video_src
)))
853 WARN("Failed to create video source node, hr %#x.\n", hr
);
855 if (FAILED(hr
= media_engine_create_video_renderer(engine
, &grabber_node
)))
856 WARN("Failed to create video grabber node, hr %#x.\n", hr
);
858 if (grabber_node
&& video_src
)
860 IMFTopology_AddNode(topology
, video_src
);
861 IMFTopology_AddNode(topology
, grabber_node
);
862 IMFTopologyNode_ConnectOutput(video_src
, 0, grabber_node
, 0);
866 IMFTopologyNode_GetTopoNodeID(video_src
, &engine
->video_frame
.node_id
);
869 IMFTopologyNode_Release(grabber_node
);
871 IMFTopologyNode_Release(video_src
);
875 hr
= IMFMediaSession_SetTopology(engine
->session
, MFSESSION_SETTOPOLOGY_IMMEDIATE
, topology
);
879 IMFTopology_Release(topology
);
882 IMFStreamDescriptor_Release(sd_video
);
884 IMFStreamDescriptor_Release(sd_audio
);
886 IMFPresentationDescriptor_Release(pd
);
891 static HRESULT WINAPI
media_engine_load_handler_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
893 struct media_engine
*engine
= impl_from_load_handler_IMFAsyncCallback(iface
);
894 MF_OBJECT_TYPE obj_type
;
895 IMFMediaSource
*source
;
896 IUnknown
*object
= NULL
;
899 EnterCriticalSection(&engine
->cs
);
901 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_LOADSTART
, 0, 0);
903 if (FAILED(hr
= IMFSourceResolver_EndCreateObjectFromURL(engine
->resolver
, result
, &obj_type
, &object
)))
904 WARN("Failed to create source object, hr %#x.\n", hr
);
908 if (SUCCEEDED(hr
= IUnknown_QueryInterface(object
, &IID_IMFMediaSource
, (void **)&source
)))
910 hr
= media_engine_create_topology(engine
, source
);
911 IMFMediaSource_Release(source
);
913 IUnknown_Release(object
);
918 engine
->error_code
= MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED
;
919 engine
->extended_code
= hr
;
920 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_ERROR
, engine
->error_code
,
921 engine
->extended_code
);
924 LeaveCriticalSection(&engine
->cs
);
929 static const IMFAsyncCallbackVtbl media_engine_load_handler_vtbl
=
931 media_engine_callback_QueryInterface
,
932 media_engine_load_handler_AddRef
,
933 media_engine_load_handler_Release
,
934 media_engine_callback_GetParameters
,
935 media_engine_load_handler_Invoke
,
938 static HRESULT WINAPI
media_engine_QueryInterface(IMFMediaEngine
*iface
, REFIID riid
, void **obj
)
940 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
942 if (IsEqualIID(riid
, &IID_IMFMediaEngine
) ||
943 IsEqualIID(riid
, &IID_IUnknown
))
946 IMFMediaEngine_AddRef(iface
);
950 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
952 return E_NOINTERFACE
;
955 static ULONG WINAPI
media_engine_AddRef(IMFMediaEngine
*iface
)
957 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
958 ULONG refcount
= InterlockedIncrement(&engine
->refcount
);
960 TRACE("%p, refcount %u.\n", iface
, refcount
);
965 static void free_media_engine(struct media_engine
*engine
)
967 if (engine
->callback
)
968 IMFMediaEngineNotify_Release(engine
->callback
);
970 IMFPresentationClock_Release(engine
->clock
);
972 IMFMediaSession_Release(engine
->session
);
973 if (engine
->attributes
)
974 IMFAttributes_Release(engine
->attributes
);
975 if (engine
->resolver
)
976 IMFSourceResolver_Release(engine
->resolver
);
977 SysFreeString(engine
->current_source
);
978 DeleteCriticalSection(&engine
->cs
);
982 static ULONG WINAPI
media_engine_Release(IMFMediaEngine
*iface
)
984 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
985 ULONG refcount
= InterlockedDecrement(&engine
->refcount
);
987 TRACE("%p, refcount %u.\n", iface
, refcount
);
990 free_media_engine(engine
);
995 static HRESULT WINAPI
media_engine_GetError(IMFMediaEngine
*iface
, IMFMediaError
**error
)
997 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1000 TRACE("%p, %p.\n", iface
, error
);
1004 EnterCriticalSection(&engine
->cs
);
1005 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1007 else if (engine
->error_code
)
1009 if (SUCCEEDED(hr
= create_media_error(error
)))
1011 IMFMediaError_SetErrorCode(*error
, engine
->error_code
);
1012 IMFMediaError_SetExtendedErrorCode(*error
, engine
->extended_code
);
1015 LeaveCriticalSection(&engine
->cs
);
1020 static HRESULT WINAPI
media_engine_SetErrorCode(IMFMediaEngine
*iface
, MF_MEDIA_ENGINE_ERR code
)
1022 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1025 TRACE("%p, %u.\n", iface
, code
);
1027 if ((unsigned int)code
> MF_MEDIA_ENGINE_ERR_ENCRYPTED
)
1028 return E_INVALIDARG
;
1030 EnterCriticalSection(&engine
->cs
);
1031 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1034 engine
->error_code
= code
;
1035 LeaveCriticalSection(&engine
->cs
);
1040 static HRESULT WINAPI
media_engine_SetSourceElements(IMFMediaEngine
*iface
, IMFMediaEngineSrcElements
*elements
)
1042 FIXME("(%p, %p): stub.\n", iface
, elements
);
1047 static HRESULT WINAPI
media_engine_SetSource(IMFMediaEngine
*iface
, BSTR url
)
1049 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1052 TRACE("%p, %s.\n", iface
, debugstr_w(url
));
1054 EnterCriticalSection(&engine
->cs
);
1056 SysFreeString(engine
->current_source
);
1057 engine
->current_source
= NULL
;
1059 engine
->current_source
= SysAllocString(url
);
1061 engine
->ready_state
= MF_MEDIA_ENGINE_READY_HAVE_NOTHING
;
1063 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS
, 0, 0);
1067 IPropertyStore
*props
= NULL
;
1070 flags
= MF_RESOLUTION_MEDIASOURCE
;
1071 if (engine
->flags
& MF_MEDIA_ENGINE_DISABLE_LOCAL_PLUGINS
)
1072 flags
|= MF_RESOLUTION_DISABLE_LOCAL_PLUGINS
;
1074 IMFAttributes_GetUnknown(engine
->attributes
, &MF_MEDIA_ENGINE_SOURCE_RESOLVER_CONFIG_STORE
,
1075 &IID_IPropertyStore
, (void **)&props
);
1076 hr
= IMFSourceResolver_BeginCreateObjectFromURL(engine
->resolver
, url
, flags
, props
, NULL
, &engine
->load_handler
, NULL
);
1078 IPropertyStore_Release(props
);
1081 LeaveCriticalSection(&engine
->cs
);
1086 static HRESULT WINAPI
media_engine_GetCurrentSource(IMFMediaEngine
*iface
, BSTR
*url
)
1088 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1091 TRACE("%p, %p.\n", iface
, url
);
1095 EnterCriticalSection(&engine
->cs
);
1096 if (engine
->current_source
)
1098 if (!(*url
= SysAllocString(engine
->current_source
)))
1101 LeaveCriticalSection(&engine
->cs
);
1106 static USHORT WINAPI
media_engine_GetNetworkState(IMFMediaEngine
*iface
)
1108 FIXME("(%p): stub.\n", iface
);
1113 static MF_MEDIA_ENGINE_PRELOAD WINAPI
media_engine_GetPreload(IMFMediaEngine
*iface
)
1115 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1116 MF_MEDIA_ENGINE_PRELOAD preload
;
1118 TRACE("%p.\n", iface
);
1120 EnterCriticalSection(&engine
->cs
);
1121 preload
= engine
->preload
;
1122 LeaveCriticalSection(&engine
->cs
);
1127 static HRESULT WINAPI
media_engine_SetPreload(IMFMediaEngine
*iface
, MF_MEDIA_ENGINE_PRELOAD preload
)
1129 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1131 TRACE("%p, %d.\n", iface
, preload
);
1133 EnterCriticalSection(&engine
->cs
);
1134 engine
->preload
= preload
;
1135 LeaveCriticalSection(&engine
->cs
);
1140 static HRESULT WINAPI
media_engine_GetBuffered(IMFMediaEngine
*iface
, IMFMediaTimeRange
**range
)
1142 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1145 TRACE("%p, %p.\n", iface
, range
);
1147 if (FAILED(hr
= create_time_range(range
)))
1150 EnterCriticalSection(&engine
->cs
);
1151 if (!isnan(engine
->duration
))
1152 hr
= IMFMediaTimeRange_AddRange(*range
, 0.0, engine
->duration
);
1153 LeaveCriticalSection(&engine
->cs
);
1158 static HRESULT WINAPI
media_engine_Load(IMFMediaEngine
*iface
)
1160 FIXME("(%p): stub.\n", iface
);
1165 static HRESULT WINAPI
media_engine_CanPlayType(IMFMediaEngine
*iface
, BSTR type
, MF_MEDIA_ENGINE_CANPLAY
*answer
)
1167 FIXME("(%p, %s, %p): stub.\n", iface
, debugstr_w(type
), answer
);
1172 static USHORT WINAPI
media_engine_GetReadyState(IMFMediaEngine
*iface
)
1174 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1175 unsigned short state
;
1177 TRACE("%p.\n", iface
);
1179 EnterCriticalSection(&engine
->cs
);
1180 state
= engine
->ready_state
;
1181 LeaveCriticalSection(&engine
->cs
);
1186 static BOOL WINAPI
media_engine_IsSeeking(IMFMediaEngine
*iface
)
1188 FIXME("(%p): stub.\n", iface
);
1193 static double WINAPI
media_engine_GetCurrentTime(IMFMediaEngine
*iface
)
1195 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1199 TRACE("%p.\n", iface
);
1201 EnterCriticalSection(&engine
->cs
);
1202 if (engine
->flags
& FLAGS_ENGINE_IS_ENDED
)
1204 ret
= engine
->duration
;
1206 else if (SUCCEEDED(IMFPresentationClock_GetTime(engine
->clock
, &clocktime
)))
1208 ret
= (double)clocktime
/ 10000000.0;
1210 LeaveCriticalSection(&engine
->cs
);
1215 static HRESULT WINAPI
media_engine_SetCurrentTime(IMFMediaEngine
*iface
, double time
)
1217 FIXME("(%p, %f): stub.\n", iface
, time
);
1222 static double WINAPI
media_engine_GetStartTime(IMFMediaEngine
*iface
)
1224 FIXME("(%p): stub.\n", iface
);
1229 static double WINAPI
media_engine_GetDuration(IMFMediaEngine
*iface
)
1231 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1234 TRACE("%p.\n", iface
);
1236 EnterCriticalSection(&engine
->cs
);
1237 value
= engine
->duration
;
1238 LeaveCriticalSection(&engine
->cs
);
1243 static BOOL WINAPI
media_engine_IsPaused(IMFMediaEngine
*iface
)
1245 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1248 TRACE("%p.\n", iface
);
1250 EnterCriticalSection(&engine
->cs
);
1251 value
= !!(engine
->flags
& FLAGS_ENGINE_PAUSED
);
1252 LeaveCriticalSection(&engine
->cs
);
1257 static double WINAPI
media_engine_GetDefaultPlaybackRate(IMFMediaEngine
*iface
)
1259 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1262 TRACE("%p.\n", iface
);
1264 EnterCriticalSection(&engine
->cs
);
1265 rate
= engine
->default_playback_rate
;
1266 LeaveCriticalSection(&engine
->cs
);
1271 static HRESULT WINAPI
media_engine_SetDefaultPlaybackRate(IMFMediaEngine
*iface
, double rate
)
1273 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1276 TRACE("%p, %f.\n", iface
, rate
);
1278 EnterCriticalSection(&engine
->cs
);
1279 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1281 else if (engine
->default_playback_rate
!= rate
)
1283 engine
->default_playback_rate
= rate
;
1284 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_RATECHANGE
, 0, 0);
1286 LeaveCriticalSection(&engine
->cs
);
1291 static double WINAPI
media_engine_GetPlaybackRate(IMFMediaEngine
*iface
)
1293 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1296 TRACE("%p.\n", iface
);
1298 EnterCriticalSection(&engine
->cs
);
1299 rate
= engine
->playback_rate
;
1300 LeaveCriticalSection(&engine
->cs
);
1305 static HRESULT WINAPI
media_engine_SetPlaybackRate(IMFMediaEngine
*iface
, double rate
)
1307 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1310 TRACE("%p, %f.\n", iface
, rate
);
1312 EnterCriticalSection(&engine
->cs
);
1313 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1315 else if (engine
->playback_rate
!= rate
)
1317 engine
->playback_rate
= rate
;
1318 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_RATECHANGE
, 0, 0);
1320 LeaveCriticalSection(&engine
->cs
);
1325 static HRESULT WINAPI
media_engine_GetPlayed(IMFMediaEngine
*iface
, IMFMediaTimeRange
**played
)
1327 FIXME("(%p, %p): stub.\n", iface
, played
);
1332 static HRESULT WINAPI
media_engine_GetSeekable(IMFMediaEngine
*iface
, IMFMediaTimeRange
**seekable
)
1334 FIXME("(%p, %p): stub.\n", iface
, seekable
);
1339 static BOOL WINAPI
media_engine_IsEnded(IMFMediaEngine
*iface
)
1341 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1344 TRACE("%p.\n", iface
);
1346 EnterCriticalSection(&engine
->cs
);
1347 value
= !!(engine
->flags
& FLAGS_ENGINE_IS_ENDED
);
1348 LeaveCriticalSection(&engine
->cs
);
1353 static BOOL WINAPI
media_engine_GetAutoPlay(IMFMediaEngine
*iface
)
1355 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1358 TRACE("%p.\n", iface
);
1360 EnterCriticalSection(&engine
->cs
);
1361 value
= !!(engine
->flags
& FLAGS_ENGINE_AUTO_PLAY
);
1362 LeaveCriticalSection(&engine
->cs
);
1367 static HRESULT WINAPI
media_engine_SetAutoPlay(IMFMediaEngine
*iface
, BOOL autoplay
)
1369 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1371 FIXME("(%p, %d): stub.\n", iface
, autoplay
);
1373 EnterCriticalSection(&engine
->cs
);
1374 media_engine_set_flag(engine
, FLAGS_ENGINE_AUTO_PLAY
, autoplay
);
1375 LeaveCriticalSection(&engine
->cs
);
1380 static BOOL WINAPI
media_engine_GetLoop(IMFMediaEngine
*iface
)
1382 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1385 TRACE("%p.\n", iface
);
1387 EnterCriticalSection(&engine
->cs
);
1388 value
= !!(engine
->flags
& FLAGS_ENGINE_LOOP
);
1389 LeaveCriticalSection(&engine
->cs
);
1394 static HRESULT WINAPI
media_engine_SetLoop(IMFMediaEngine
*iface
, BOOL loop
)
1396 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1398 FIXME("(%p, %d): stub.\n", iface
, loop
);
1400 EnterCriticalSection(&engine
->cs
);
1401 media_engine_set_flag(engine
, FLAGS_ENGINE_LOOP
, loop
);
1402 LeaveCriticalSection(&engine
->cs
);
1407 static HRESULT WINAPI
media_engine_Play(IMFMediaEngine
*iface
)
1409 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1412 TRACE("%p.\n", iface
);
1414 EnterCriticalSection(&engine
->cs
);
1416 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS
, 0, 0);
1418 if (!(engine
->flags
& FLAGS_ENGINE_WAITING
))
1420 media_engine_set_flag(engine
, FLAGS_ENGINE_PAUSED
| FLAGS_ENGINE_IS_ENDED
, FALSE
);
1421 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PLAY
, 0, 0);
1424 IMFMediaSession_Start(engine
->session
, &GUID_NULL
, &var
);
1426 media_engine_set_flag(engine
, FLAGS_ENGINE_WAITING
, TRUE
);
1429 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_WAITING
, 0, 0);
1431 LeaveCriticalSection(&engine
->cs
);
1436 static HRESULT WINAPI
media_engine_Pause(IMFMediaEngine
*iface
)
1438 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1440 TRACE("%p.\n", iface
);
1442 EnterCriticalSection(&engine
->cs
);
1444 if (!(engine
->flags
& FLAGS_ENGINE_PAUSED
))
1446 media_engine_set_flag(engine
, FLAGS_ENGINE_WAITING
| FLAGS_ENGINE_IS_ENDED
, FALSE
);
1447 media_engine_set_flag(engine
, FLAGS_ENGINE_PAUSED
, TRUE
);
1449 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_TIMEUPDATE
, 0, 0);
1450 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PAUSE
, 0, 0);
1453 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS
, 0, 0);
1455 LeaveCriticalSection(&engine
->cs
);
1460 static BOOL WINAPI
media_engine_GetMuted(IMFMediaEngine
*iface
)
1462 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1465 TRACE("%p.\n", iface
);
1467 EnterCriticalSection(&engine
->cs
);
1468 ret
= !!(engine
->flags
& FLAGS_ENGINE_MUTED
);
1469 LeaveCriticalSection(&engine
->cs
);
1474 static HRESULT WINAPI
media_engine_SetMuted(IMFMediaEngine
*iface
, BOOL muted
)
1476 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1479 TRACE("%p, %d.\n", iface
, muted
);
1481 EnterCriticalSection(&engine
->cs
);
1482 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1484 else if (!!(engine
->flags
& FLAGS_ENGINE_MUTED
) ^ !!muted
)
1486 media_engine_set_flag(engine
, FLAGS_ENGINE_MUTED
, muted
);
1487 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE
, 0, 0);
1489 LeaveCriticalSection(&engine
->cs
);
1494 static double WINAPI
media_engine_GetVolume(IMFMediaEngine
*iface
)
1496 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1499 TRACE("%p.\n", iface
);
1501 EnterCriticalSection(&engine
->cs
);
1502 volume
= engine
->volume
;
1503 LeaveCriticalSection(&engine
->cs
);
1508 static HRESULT WINAPI
media_engine_SetVolume(IMFMediaEngine
*iface
, double volume
)
1510 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1513 TRACE("%p, %f.\n", iface
, volume
);
1515 EnterCriticalSection(&engine
->cs
);
1516 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1518 else if (volume
!= engine
->volume
)
1520 engine
->volume
= volume
;
1521 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE
, 0, 0);
1523 LeaveCriticalSection(&engine
->cs
);
1528 static BOOL WINAPI
media_engine_HasVideo(IMFMediaEngine
*iface
)
1530 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1533 TRACE("%p.\n", iface
);
1535 EnterCriticalSection(&engine
->cs
);
1536 value
= !!(engine
->flags
& FLAGS_ENGINE_HAS_VIDEO
);
1537 LeaveCriticalSection(&engine
->cs
);
1542 static BOOL WINAPI
media_engine_HasAudio(IMFMediaEngine
*iface
)
1544 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1547 TRACE("%p.\n", iface
);
1549 EnterCriticalSection(&engine
->cs
);
1550 value
= !!(engine
->flags
& FLAGS_ENGINE_HAS_AUDIO
);
1551 LeaveCriticalSection(&engine
->cs
);
1556 static HRESULT WINAPI
media_engine_GetNativeVideoSize(IMFMediaEngine
*iface
, DWORD
*cx
, DWORD
*cy
)
1558 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1561 TRACE("%p, %p, %p.\n", iface
, cx
, cy
);
1564 return E_INVALIDARG
;
1566 EnterCriticalSection(&engine
->cs
);
1568 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1570 else if (!engine
->video_frame
.size
.cx
&& !engine
->video_frame
.size
.cy
)
1574 if (cx
) *cx
= engine
->video_frame
.size
.cx
;
1575 if (cy
) *cy
= engine
->video_frame
.size
.cy
;
1578 LeaveCriticalSection(&engine
->cs
);
1583 static HRESULT WINAPI
media_engine_GetVideoAspectRatio(IMFMediaEngine
*iface
, DWORD
*cx
, DWORD
*cy
)
1585 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1588 TRACE("%p, %p, %p.\n", iface
, cx
, cy
);
1591 return E_INVALIDARG
;
1593 EnterCriticalSection(&engine
->cs
);
1595 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1597 else if (!engine
->video_frame
.size
.cx
&& !engine
->video_frame
.size
.cy
)
1601 if (cx
) *cx
= engine
->video_frame
.ratio
.cx
;
1602 if (cy
) *cy
= engine
->video_frame
.ratio
.cy
;
1605 LeaveCriticalSection(&engine
->cs
);
1610 static HRESULT WINAPI
media_engine_Shutdown(IMFMediaEngine
*iface
)
1612 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1615 FIXME("(%p): stub.\n", iface
);
1617 EnterCriticalSection(&engine
->cs
);
1618 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1622 media_engine_set_flag(engine
, FLAGS_ENGINE_SHUT_DOWN
, TRUE
);
1623 IMFMediaSession_Shutdown(engine
->session
);
1625 LeaveCriticalSection(&engine
->cs
);
1630 static HRESULT WINAPI
media_engine_TransferVideoFrame(IMFMediaEngine
*iface
, IUnknown
*surface
,
1631 const MFVideoNormalizedRect
*src
,
1632 const RECT
*dst
, const MFARGB
*color
)
1634 FIXME("(%p, %p, %p, %p, %p): stub.\n", iface
, surface
, src
, dst
, color
);
1639 static HRESULT WINAPI
media_engine_OnVideoStreamTick(IMFMediaEngine
*iface
, LONGLONG
*pts
)
1641 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1644 TRACE("%p, %p.\n", iface
, pts
);
1646 EnterCriticalSection(&engine
->cs
);
1648 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1654 *pts
= engine
->video_frame
.pts
;
1655 hr
= *pts
== MINLONGLONG
? S_FALSE
: S_OK
;
1658 LeaveCriticalSection(&engine
->cs
);
1663 static const IMFMediaEngineVtbl media_engine_vtbl
=
1665 media_engine_QueryInterface
,
1666 media_engine_AddRef
,
1667 media_engine_Release
,
1668 media_engine_GetError
,
1669 media_engine_SetErrorCode
,
1670 media_engine_SetSourceElements
,
1671 media_engine_SetSource
,
1672 media_engine_GetCurrentSource
,
1673 media_engine_GetNetworkState
,
1674 media_engine_GetPreload
,
1675 media_engine_SetPreload
,
1676 media_engine_GetBuffered
,
1678 media_engine_CanPlayType
,
1679 media_engine_GetReadyState
,
1680 media_engine_IsSeeking
,
1681 media_engine_GetCurrentTime
,
1682 media_engine_SetCurrentTime
,
1683 media_engine_GetStartTime
,
1684 media_engine_GetDuration
,
1685 media_engine_IsPaused
,
1686 media_engine_GetDefaultPlaybackRate
,
1687 media_engine_SetDefaultPlaybackRate
,
1688 media_engine_GetPlaybackRate
,
1689 media_engine_SetPlaybackRate
,
1690 media_engine_GetPlayed
,
1691 media_engine_GetSeekable
,
1692 media_engine_IsEnded
,
1693 media_engine_GetAutoPlay
,
1694 media_engine_SetAutoPlay
,
1695 media_engine_GetLoop
,
1696 media_engine_SetLoop
,
1699 media_engine_GetMuted
,
1700 media_engine_SetMuted
,
1701 media_engine_GetVolume
,
1702 media_engine_SetVolume
,
1703 media_engine_HasVideo
,
1704 media_engine_HasAudio
,
1705 media_engine_GetNativeVideoSize
,
1706 media_engine_GetVideoAspectRatio
,
1707 media_engine_Shutdown
,
1708 media_engine_TransferVideoFrame
,
1709 media_engine_OnVideoStreamTick
,
1712 static HRESULT WINAPI
media_engine_grabber_callback_QueryInterface(IMFSampleGrabberSinkCallback
*iface
,
1713 REFIID riid
, void **obj
)
1715 if (IsEqualIID(riid
, &IID_IMFSampleGrabberSinkCallback
) ||
1716 IsEqualIID(riid
, &IID_IUnknown
))
1719 IMFSampleGrabberSinkCallback_AddRef(iface
);
1724 return E_NOINTERFACE
;
1727 static ULONG WINAPI
media_engine_grabber_callback_AddRef(IMFSampleGrabberSinkCallback
*iface
)
1729 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
1730 return IMFMediaEngine_AddRef(&engine
->IMFMediaEngine_iface
);
1733 static ULONG WINAPI
media_engine_grabber_callback_Release(IMFSampleGrabberSinkCallback
*iface
)
1735 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
1736 return IMFMediaEngine_Release(&engine
->IMFMediaEngine_iface
);
1739 static HRESULT WINAPI
media_engine_grabber_callback_OnClockStart(IMFSampleGrabberSinkCallback
*iface
,
1740 MFTIME systime
, LONGLONG start_offset
)
1745 static HRESULT WINAPI
media_engine_grabber_callback_OnClockStop(IMFSampleGrabberSinkCallback
*iface
,
1748 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
1750 EnterCriticalSection(&engine
->cs
);
1751 media_engine_set_flag(engine
, FLAGS_ENGINE_FIRST_FRAME
, FALSE
);
1752 engine
->video_frame
.pts
= MINLONGLONG
;
1753 LeaveCriticalSection(&engine
->cs
);
1758 static HRESULT WINAPI
media_engine_grabber_callback_OnClockPause(IMFSampleGrabberSinkCallback
*iface
,
1764 static HRESULT WINAPI
media_engine_grabber_callback_OnClockRestart(IMFSampleGrabberSinkCallback
*iface
,
1770 static HRESULT WINAPI
media_engine_grabber_callback_OnClockSetRate(IMFSampleGrabberSinkCallback
*iface
,
1771 MFTIME systime
, float rate
)
1776 static HRESULT WINAPI
media_engine_grabber_callback_OnSetPresentationClock(IMFSampleGrabberSinkCallback
*iface
,
1777 IMFPresentationClock
*clock
)
1782 static HRESULT WINAPI
media_engine_grabber_callback_OnProcessSample(IMFSampleGrabberSinkCallback
*iface
,
1783 REFGUID major_type
, DWORD sample_flags
, LONGLONG sample_time
, LONGLONG sample_duration
,
1784 const BYTE
*buffer
, DWORD sample_size
)
1786 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
1788 EnterCriticalSection(&engine
->cs
);
1790 if (!(engine
->flags
& FLAGS_ENGINE_FIRST_FRAME
))
1792 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY
, 0, 0);
1793 media_engine_set_flag(engine
, FLAGS_ENGINE_FIRST_FRAME
, TRUE
);
1795 engine
->video_frame
.pts
= sample_time
;
1797 LeaveCriticalSection(&engine
->cs
);
1802 static HRESULT WINAPI
media_engine_grabber_callback_OnShutdown(IMFSampleGrabberSinkCallback
*iface
)
1807 static const IMFSampleGrabberSinkCallbackVtbl media_engine_grabber_callback_vtbl
=
1809 media_engine_grabber_callback_QueryInterface
,
1810 media_engine_grabber_callback_AddRef
,
1811 media_engine_grabber_callback_Release
,
1812 media_engine_grabber_callback_OnClockStart
,
1813 media_engine_grabber_callback_OnClockStop
,
1814 media_engine_grabber_callback_OnClockPause
,
1815 media_engine_grabber_callback_OnClockRestart
,
1816 media_engine_grabber_callback_OnClockSetRate
,
1817 media_engine_grabber_callback_OnSetPresentationClock
,
1818 media_engine_grabber_callback_OnProcessSample
,
1819 media_engine_grabber_callback_OnShutdown
,
1822 static HRESULT WINAPI
media_engine_factory_QueryInterface(IMFMediaEngineClassFactory
*iface
, REFIID riid
, void **obj
)
1824 if (IsEqualIID(riid
, &IID_IMFMediaEngineClassFactory
) ||
1825 IsEqualIID(riid
, &IID_IUnknown
))
1828 IMFMediaEngineClassFactory_AddRef(iface
);
1832 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
1834 return E_NOINTERFACE
;
1837 static ULONG WINAPI
media_engine_factory_AddRef(IMFMediaEngineClassFactory
*iface
)
1842 static ULONG WINAPI
media_engine_factory_Release(IMFMediaEngineClassFactory
*iface
)
1847 static HRESULT
init_media_engine(DWORD flags
, IMFAttributes
*attributes
, struct media_engine
*engine
)
1849 DXGI_FORMAT output_format
;
1850 UINT64 playback_hwnd
;
1854 engine
->IMFMediaEngine_iface
.lpVtbl
= &media_engine_vtbl
;
1855 engine
->session_events
.lpVtbl
= &media_engine_session_events_vtbl
;
1856 engine
->load_handler
.lpVtbl
= &media_engine_load_handler_vtbl
;
1857 engine
->grabber_callback
.lpVtbl
= &media_engine_grabber_callback_vtbl
;
1858 engine
->refcount
= 1;
1859 engine
->flags
= (flags
& MF_MEDIA_ENGINE_CREATEFLAGS_MASK
) | FLAGS_ENGINE_PAUSED
;
1860 engine
->default_playback_rate
= 1.0;
1861 engine
->playback_rate
= 1.0;
1862 engine
->volume
= 1.0;
1863 engine
->duration
= NAN
;
1864 engine
->video_frame
.pts
= MINLONGLONG
;
1865 InitializeCriticalSection(&engine
->cs
);
1867 hr
= IMFAttributes_GetUnknown(attributes
, &MF_MEDIA_ENGINE_CALLBACK
, &IID_IMFMediaEngineNotify
,
1868 (void **)&engine
->callback
);
1872 if (FAILED(hr
= MFCreateMediaSession(NULL
, &engine
->session
)))
1875 if (FAILED(hr
= IMFMediaSession_GetClock(engine
->session
, &clock
)))
1878 hr
= IMFClock_QueryInterface(clock
, &IID_IMFPresentationClock
, (void **)&engine
->clock
);
1879 IMFClock_Release(clock
);
1883 if (FAILED(hr
= IMFMediaSession_BeginGetEvent(engine
->session
, &engine
->session_events
, NULL
)))
1886 if (FAILED(hr
= MFCreateSourceResolver(&engine
->resolver
)))
1889 if (FAILED(hr
= MFCreateAttributes(&engine
->attributes
, 0)))
1892 if (FAILED(hr
= IMFAttributes_CopyAllItems(attributes
, engine
->attributes
)))
1895 IMFAttributes_GetUINT64(attributes
, &MF_MEDIA_ENGINE_PLAYBACK_HWND
, &playback_hwnd
);
1896 hr
= IMFAttributes_GetUINT32(attributes
, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT
, &output_format
);
1897 if (playback_hwnd
) /* FIXME: handle MF_MEDIA_ENGINE_PLAYBACK_VISUAL */
1898 engine
->mode
= MEDIA_ENGINE_RENDERING_MODE
;
1902 engine
->mode
= MEDIA_ENGINE_FRAME_SERVER_MODE
;
1904 engine
->mode
= MEDIA_ENGINE_AUDIO_MODE
;
1910 static HRESULT WINAPI
media_engine_factory_CreateInstance(IMFMediaEngineClassFactory
*iface
, DWORD flags
,
1911 IMFAttributes
*attributes
, IMFMediaEngine
**engine
)
1913 struct media_engine
*object
;
1916 TRACE("%p, %#x, %p, %p.\n", iface
, flags
, attributes
, engine
);
1918 if (!attributes
|| !engine
)
1921 object
= calloc(1, sizeof(*object
));
1923 return E_OUTOFMEMORY
;
1925 hr
= init_media_engine(flags
, attributes
, object
);
1928 free_media_engine(object
);
1932 *engine
= &object
->IMFMediaEngine_iface
;
1937 static HRESULT WINAPI
media_engine_factory_CreateTimeRange(IMFMediaEngineClassFactory
*iface
,
1938 IMFMediaTimeRange
**range
)
1940 TRACE("%p, %p.\n", iface
, range
);
1942 return create_time_range(range
);
1945 static HRESULT WINAPI
media_engine_factory_CreateError(IMFMediaEngineClassFactory
*iface
, IMFMediaError
**error
)
1947 TRACE("%p, %p.\n", iface
, error
);
1949 return create_media_error(error
);
1952 static const IMFMediaEngineClassFactoryVtbl media_engine_factory_vtbl
=
1954 media_engine_factory_QueryInterface
,
1955 media_engine_factory_AddRef
,
1956 media_engine_factory_Release
,
1957 media_engine_factory_CreateInstance
,
1958 media_engine_factory_CreateTimeRange
,
1959 media_engine_factory_CreateError
,
1962 static IMFMediaEngineClassFactory media_engine_factory
= { &media_engine_factory_vtbl
};
1964 static HRESULT WINAPI
classfactory_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **obj
)
1966 TRACE("%s, %p.\n", debugstr_guid(riid
), obj
);
1968 if (IsEqualGUID(riid
, &IID_IClassFactory
) ||
1969 IsEqualGUID(riid
, &IID_IUnknown
))
1971 IClassFactory_AddRef(iface
);
1976 WARN("interface %s not implemented.\n", debugstr_guid(riid
));
1978 return E_NOINTERFACE
;
1981 static ULONG WINAPI
classfactory_AddRef(IClassFactory
*iface
)
1986 static ULONG WINAPI
classfactory_Release(IClassFactory
*iface
)
1991 static HRESULT WINAPI
classfactory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **obj
)
1993 TRACE("%p, %s, %p.\n", outer
, debugstr_guid(riid
), obj
);
1998 return CLASS_E_NOAGGREGATION
;
2000 return IMFMediaEngineClassFactory_QueryInterface(&media_engine_factory
, riid
, obj
);
2003 static HRESULT WINAPI
classfactory_LockServer(IClassFactory
*iface
, BOOL dolock
)
2005 FIXME("(%d): stub.\n", dolock
);
2009 static const IClassFactoryVtbl class_factory_vtbl
=
2011 classfactory_QueryInterface
,
2012 classfactory_AddRef
,
2013 classfactory_Release
,
2014 classfactory_CreateInstance
,
2015 classfactory_LockServer
,
2018 static IClassFactory classfactory
= { &class_factory_vtbl
};
2020 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID riid
, void **obj
)
2022 TRACE("%s, %s, %p.\n", debugstr_guid(clsid
), debugstr_guid(riid
), obj
);
2024 if (IsEqualGUID(clsid
, &CLSID_MFMediaEngineClassFactory
))
2025 return IClassFactory_QueryInterface(&classfactory
, riid
, obj
);
2027 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2029 return CLASS_E_CLASSNOTAVAILABLE
;
2032 HRESULT WINAPI
DllCanUnloadNow(void)