mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / mfmediaengine / main.c
bloba606ce364af25d47d4c72d8c03e455d2bca482ae
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"
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;
39 void *new_elements;
41 if (count <= *capacity)
42 return TRUE;
44 max_capacity = ~(SIZE_T)0 / size;
45 if (count > max_capacity)
46 return FALSE;
48 new_capacity = max(4, *capacity);
49 while (new_capacity < count && new_capacity <= max_capacity / 2)
50 new_capacity *= 2;
51 if (new_capacity < count)
52 new_capacity = max_capacity;
54 if (!(new_elements = realloc(*elements, new_capacity * size)))
55 return FALSE;
57 *elements = new_elements;
58 *capacity = new_capacity;
60 return TRUE;
63 enum media_engine_mode
65 MEDIA_ENGINE_INVALID,
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,
87 struct video_frame
89 LONGLONG pts;
90 SIZE size;
91 SIZE ratio;
92 TOPOID node_id;
95 struct media_engine
97 IMFMediaEngine IMFMediaEngine_iface;
98 IMFAsyncCallback session_events;
99 IMFAsyncCallback load_handler;
100 IMFSampleGrabberSinkCallback grabber_callback;
101 LONG refcount;
102 IMFMediaEngineNotify *callback;
103 IMFAttributes *attributes;
104 enum media_engine_mode mode;
105 unsigned int flags;
106 double playback_rate;
107 double default_playback_rate;
108 double volume;
109 double duration;
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;
117 BSTR current_source;
118 struct video_frame video_frame;
119 CRITICAL_SECTION cs;
122 struct range
124 double start;
125 double end;
128 struct time_range
130 IMFMediaTimeRange IMFMediaTimeRange_iface;
131 LONG refcount;
133 struct range *ranges;
134 size_t count;
135 size_t capacity;
138 static struct time_range *impl_from_IMFMediaTimeRange(IMFMediaTimeRange *iface)
140 return CONTAINING_RECORD(iface, struct time_range, IMFMediaTimeRange_iface);
143 struct media_error
145 IMFMediaError IMFMediaError_iface;
146 LONG refcount;
147 unsigned int code;
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))
163 *obj = iface;
164 IMFMediaError_AddRef(iface);
165 return S_OK;
168 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
169 *obj = NULL;
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);
180 return 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);
190 if (!refcount)
191 free(me);
193 return refcount;
196 static USHORT WINAPI media_error_GetErrorCode(IMFMediaError *iface)
198 struct media_error *me = impl_from_IMFMediaError(iface);
199 TRACE("%p.\n", iface);
200 return me->code;
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)
217 return E_INVALIDARG;
219 me->code = code;
221 return S_OK;
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;
232 return S_OK;
235 static const IMFMediaErrorVtbl media_error_vtbl =
237 media_error_QueryInterface,
238 media_error_AddRef,
239 media_error_Release,
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;
250 *ret = NULL;
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;
260 return S_OK;
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))
270 *obj = iface;
271 IMFMediaTimeRange_AddRef(iface);
272 return S_OK;
275 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
276 *obj = NULL;
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);
287 return 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);
297 if (!refcount)
299 free(range->ranges);
300 free(range);
303 return refcount;
306 static DWORD WINAPI time_range_GetLength(IMFMediaTimeRange *iface)
308 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
310 TRACE("%p.\n", iface);
312 return range->count;
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)
322 return E_INVALIDARG;
324 *start = range->ranges[idx].start;
326 return S_OK;
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)
336 return E_INVALIDARG;
338 *end = range->ranges[idx].end;
340 return S_OK;
343 static BOOL WINAPI time_range_ContainsTime(IMFMediaTimeRange *iface, double time)
345 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
346 size_t i;
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)
353 return TRUE;
356 return FALSE;
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);
365 if (range->count)
367 FIXME("Range merging is not implemented.\n");
368 return E_NOTIMPL;
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;
376 range->count++;
378 return S_OK;
381 static HRESULT WINAPI time_range_Clear(IMFMediaTimeRange *iface)
383 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
385 TRACE("%p.\n", iface);
387 range->count = 0;
389 return S_OK;
392 static const IMFMediaTimeRangeVtbl time_range_vtbl =
394 time_range_QueryInterface,
395 time_range_AddRef,
396 time_range_Release,
397 time_range_GetLength,
398 time_range_GetStart,
399 time_range_GetEnd,
400 time_range_ContainsTime,
401 time_range_AddRange,
402 time_range_Clear,
405 static HRESULT create_time_range(IMFMediaTimeRange **range)
407 struct time_range *object;
409 object = calloc(1, sizeof(*object));
410 if (!object)
411 return E_OUTOFMEMORY;
413 object->IMFMediaTimeRange_iface.lpVtbl = &time_range_vtbl;
414 object->refcount = 1;
416 *range = &object->IMFMediaTimeRange_iface;
418 return S_OK;
421 static void media_engine_set_flag(struct media_engine *engine, unsigned int mask, BOOL value)
423 if (value)
424 engine->flags |= mask;
425 else
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)
451 unsigned int m;
453 while (b)
455 m = a % b;
456 a = b;
457 b = m;
460 return a;
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;
469 unsigned int gcd;
470 UINT64 size;
471 HRESULT hr;
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)))
479 return;
481 hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR,
482 &IID_IMFStreamDescriptor, (void **)&sd);
483 IMFTopologyNode_Release(node);
484 if (FAILED(hr))
485 return;
487 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
488 IMFStreamDescriptor_Release(sd);
489 if (FAILED(hr))
490 return;
492 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &media_type);
493 IMFMediaTypeHandler_Release(handler);
494 if (FAILED(hr))
496 WARN("Failed to get current media type %#x.\n", hr);
497 return;
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))
519 *obj = iface;
520 IMFAsyncCallback_AddRef(iface);
521 return S_OK;
524 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
525 *obj = NULL;
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)
543 return E_NOTIMPL;
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;
551 HRESULT hr;
553 if (FAILED(hr = IMFMediaSession_EndGetEvent(engine->session, result, &event)))
555 WARN("Failed to get session event, hr %#x.\n", hr);
556 goto failed;
559 if (FAILED(hr = IMFMediaEvent_GetType(event, &event_type)))
561 WARN("Failed to get event type, hr %#x.\n", hr);
562 goto failed;
565 switch (event_type)
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);
572 break;
573 case MESessionTopologyStatus:
575 UINT32 topo_status = 0;
576 IMFTopology *topology;
577 PROPVARIANT value;
579 IMFMediaEvent_GetUINT32(event, &MF_EVENT_TOPOLOGY_STATUS, &topo_status);
580 if (topo_status != MF_TOPOSTATUS_READY)
581 break;
583 value.vt = VT_EMPTY;
584 if (FAILED(IMFMediaEvent_GetValue(event, &value)))
585 break;
587 if (value.vt != VT_UNKNOWN)
589 PropVariantClear(&value);
590 break;
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);
613 break;
615 case MESessionStarted:
617 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PLAYING, 0, 0);
618 break;
619 case MESessionEnded:
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);
628 break;
631 failed:
633 if (event)
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);
639 return S_OK;
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)
666 HRESULT hr;
668 if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, node)))
669 return hr;
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);
675 return S_OK;
678 static HRESULT media_engine_create_audio_renderer(struct media_engine *engine, IMFTopologyNode **node)
680 unsigned int category, role;
681 IMFActivate *sar_activate;
682 HRESULT hr;
684 *node = NULL;
686 if (FAILED(hr = MFCreateAudioRendererActivate(&sar_activate)))
687 return hr;
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);
703 return hr;
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;
711 GUID subtype;
712 HRESULT hr;
714 *node = NULL;
716 if (FAILED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, &output_format)))
718 WARN("Output format was not specified.\n");
719 return E_FAIL;
722 memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype));
723 if (!(subtype.Data1 = MFMapDXGIFormatToDX9Format(output_format)))
725 WARN("Unrecognized output format %#x.\n", output_format);
726 return E_FAIL;
729 if (FAILED(hr = MFCreateMediaType(&media_type)))
730 return hr;
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);
737 if (FAILED(hr))
738 return hr;
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);
748 return hr;
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;
757 UINT64 duration;
758 HRESULT hr;
760 memset(&engine->video_frame, 0, sizeof(engine->video_frame));
762 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd)))
763 return hr;
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;
774 BOOL selected;
776 IMFPresentationDescriptor_DeselectStream(pd, i);
778 if (sd_audio && sd_video)
779 continue;
781 IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, i, &selected, &sd);
783 if (SUCCEEDED(IMFStreamDescriptor_GetMediaTypeHandler(sd, &type_handler)))
785 GUID major = { 0 };
787 IMFMediaTypeHandler_GetMajorType(type_handler, &major);
789 if (IsEqualGUID(&major, &MFMediaType_Audio) && !sd_audio)
791 sd_audio = sd;
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))
797 sd_video = sd;
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);
809 return E_UNEXPECTED;
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;
821 else
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;
829 if (sd_audio)
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);
844 if (sar_node)
845 IMFTopologyNode_Release(sar_node);
846 if (audio_src)
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);
865 if (SUCCEEDED(hr))
866 IMFTopologyNode_GetTopoNodeID(video_src, &engine->video_frame.node_id);
868 if (grabber_node)
869 IMFTopologyNode_Release(grabber_node);
870 if (video_src)
871 IMFTopologyNode_Release(video_src);
874 if (SUCCEEDED(hr))
875 hr = IMFMediaSession_SetTopology(engine->session, MFSESSION_SETTOPOLOGY_IMMEDIATE, topology);
878 if (topology)
879 IMFTopology_Release(topology);
881 if (sd_video)
882 IMFStreamDescriptor_Release(sd_video);
883 if (sd_audio)
884 IMFStreamDescriptor_Release(sd_audio);
886 IMFPresentationDescriptor_Release(pd);
888 return hr;
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;
897 HRESULT hr;
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);
906 if (object)
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);
916 if (FAILED(hr))
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);
926 return S_OK;
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))
945 *obj = iface;
946 IMFMediaEngine_AddRef(iface);
947 return S_OK;
950 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
951 *obj = NULL;
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);
962 return refcount;
965 static void free_media_engine(struct media_engine *engine)
967 if (engine->callback)
968 IMFMediaEngineNotify_Release(engine->callback);
969 if (engine->clock)
970 IMFPresentationClock_Release(engine->clock);
971 if (engine->session)
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);
979 free(engine);
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);
989 if (!refcount)
990 free_media_engine(engine);
992 return refcount;
995 static HRESULT WINAPI media_engine_GetError(IMFMediaEngine *iface, IMFMediaError **error)
997 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
998 HRESULT hr = S_OK;
1000 TRACE("%p, %p.\n", iface, error);
1002 *error = NULL;
1004 EnterCriticalSection(&engine->cs);
1005 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1006 hr = MF_E_SHUTDOWN;
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);
1017 return hr;
1020 static HRESULT WINAPI media_engine_SetErrorCode(IMFMediaEngine *iface, MF_MEDIA_ENGINE_ERR code)
1022 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1023 HRESULT hr = S_OK;
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)
1032 hr = MF_E_SHUTDOWN;
1033 else
1034 engine->error_code = code;
1035 LeaveCriticalSection(&engine->cs);
1037 return hr;
1040 static HRESULT WINAPI media_engine_SetSourceElements(IMFMediaEngine *iface, IMFMediaEngineSrcElements *elements)
1042 FIXME("(%p, %p): stub.\n", iface, elements);
1044 return E_NOTIMPL;
1047 static HRESULT WINAPI media_engine_SetSource(IMFMediaEngine *iface, BSTR url)
1049 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1050 HRESULT hr = S_OK;
1052 TRACE("%p, %s.\n", iface, debugstr_w(url));
1054 EnterCriticalSection(&engine->cs);
1056 SysFreeString(engine->current_source);
1057 engine->current_source = NULL;
1058 if (url)
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);
1065 if (url)
1067 IPropertyStore *props = NULL;
1068 unsigned int flags;
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);
1077 if (props)
1078 IPropertyStore_Release(props);
1081 LeaveCriticalSection(&engine->cs);
1083 return hr;
1086 static HRESULT WINAPI media_engine_GetCurrentSource(IMFMediaEngine *iface, BSTR *url)
1088 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1089 HRESULT hr = S_OK;
1091 TRACE("%p, %p.\n", iface, url);
1093 *url = NULL;
1095 EnterCriticalSection(&engine->cs);
1096 if (engine->current_source)
1098 if (!(*url = SysAllocString(engine->current_source)))
1099 hr = E_OUTOFMEMORY;
1101 LeaveCriticalSection(&engine->cs);
1103 return hr;
1106 static USHORT WINAPI media_engine_GetNetworkState(IMFMediaEngine *iface)
1108 FIXME("(%p): stub.\n", iface);
1110 return 0;
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);
1124 return preload;
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);
1137 return S_OK;
1140 static HRESULT WINAPI media_engine_GetBuffered(IMFMediaEngine *iface, IMFMediaTimeRange **range)
1142 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1143 HRESULT hr;
1145 TRACE("%p, %p.\n", iface, range);
1147 if (FAILED(hr = create_time_range(range)))
1148 return hr;
1150 EnterCriticalSection(&engine->cs);
1151 if (!isnan(engine->duration))
1152 hr = IMFMediaTimeRange_AddRange(*range, 0.0, engine->duration);
1153 LeaveCriticalSection(&engine->cs);
1155 return hr;
1158 static HRESULT WINAPI media_engine_Load(IMFMediaEngine *iface)
1160 FIXME("(%p): stub.\n", iface);
1162 return E_NOTIMPL;
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);
1169 return E_NOTIMPL;
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);
1183 return state;
1186 static BOOL WINAPI media_engine_IsSeeking(IMFMediaEngine *iface)
1188 FIXME("(%p): stub.\n", iface);
1190 return FALSE;
1193 static double WINAPI media_engine_GetCurrentTime(IMFMediaEngine *iface)
1195 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1196 double ret = 0.0;
1197 MFTIME clocktime;
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);
1212 return ret;
1215 static HRESULT WINAPI media_engine_SetCurrentTime(IMFMediaEngine *iface, double time)
1217 FIXME("(%p, %f): stub.\n", iface, time);
1219 return E_NOTIMPL;
1222 static double WINAPI media_engine_GetStartTime(IMFMediaEngine *iface)
1224 FIXME("(%p): stub.\n", iface);
1226 return 0.0;
1229 static double WINAPI media_engine_GetDuration(IMFMediaEngine *iface)
1231 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1232 double value;
1234 TRACE("%p.\n", iface);
1236 EnterCriticalSection(&engine->cs);
1237 value = engine->duration;
1238 LeaveCriticalSection(&engine->cs);
1240 return value;
1243 static BOOL WINAPI media_engine_IsPaused(IMFMediaEngine *iface)
1245 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1246 BOOL value;
1248 TRACE("%p.\n", iface);
1250 EnterCriticalSection(&engine->cs);
1251 value = !!(engine->flags & FLAGS_ENGINE_PAUSED);
1252 LeaveCriticalSection(&engine->cs);
1254 return value;
1257 static double WINAPI media_engine_GetDefaultPlaybackRate(IMFMediaEngine *iface)
1259 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1260 double rate;
1262 TRACE("%p.\n", iface);
1264 EnterCriticalSection(&engine->cs);
1265 rate = engine->default_playback_rate;
1266 LeaveCriticalSection(&engine->cs);
1268 return rate;
1271 static HRESULT WINAPI media_engine_SetDefaultPlaybackRate(IMFMediaEngine *iface, double rate)
1273 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1274 HRESULT hr = S_OK;
1276 TRACE("%p, %f.\n", iface, rate);
1278 EnterCriticalSection(&engine->cs);
1279 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1280 hr = MF_E_SHUTDOWN;
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);
1288 return hr;
1291 static double WINAPI media_engine_GetPlaybackRate(IMFMediaEngine *iface)
1293 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1294 double rate;
1296 TRACE("%p.\n", iface);
1298 EnterCriticalSection(&engine->cs);
1299 rate = engine->playback_rate;
1300 LeaveCriticalSection(&engine->cs);
1302 return rate;
1305 static HRESULT WINAPI media_engine_SetPlaybackRate(IMFMediaEngine *iface, double rate)
1307 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1308 HRESULT hr = S_OK;
1310 TRACE("%p, %f.\n", iface, rate);
1312 EnterCriticalSection(&engine->cs);
1313 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1314 hr = MF_E_SHUTDOWN;
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);
1322 return hr;
1325 static HRESULT WINAPI media_engine_GetPlayed(IMFMediaEngine *iface, IMFMediaTimeRange **played)
1327 FIXME("(%p, %p): stub.\n", iface, played);
1329 return E_NOTIMPL;
1332 static HRESULT WINAPI media_engine_GetSeekable(IMFMediaEngine *iface, IMFMediaTimeRange **seekable)
1334 FIXME("(%p, %p): stub.\n", iface, seekable);
1336 return E_NOTIMPL;
1339 static BOOL WINAPI media_engine_IsEnded(IMFMediaEngine *iface)
1341 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1342 BOOL value;
1344 TRACE("%p.\n", iface);
1346 EnterCriticalSection(&engine->cs);
1347 value = !!(engine->flags & FLAGS_ENGINE_IS_ENDED);
1348 LeaveCriticalSection(&engine->cs);
1350 return value;
1353 static BOOL WINAPI media_engine_GetAutoPlay(IMFMediaEngine *iface)
1355 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1356 BOOL value;
1358 TRACE("%p.\n", iface);
1360 EnterCriticalSection(&engine->cs);
1361 value = !!(engine->flags & FLAGS_ENGINE_AUTO_PLAY);
1362 LeaveCriticalSection(&engine->cs);
1364 return value;
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);
1377 return S_OK;
1380 static BOOL WINAPI media_engine_GetLoop(IMFMediaEngine *iface)
1382 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1383 BOOL value;
1385 TRACE("%p.\n", iface);
1387 EnterCriticalSection(&engine->cs);
1388 value = !!(engine->flags & FLAGS_ENGINE_LOOP);
1389 LeaveCriticalSection(&engine->cs);
1391 return value;
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);
1404 return S_OK;
1407 static HRESULT WINAPI media_engine_Play(IMFMediaEngine *iface)
1409 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1410 PROPVARIANT var;
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);
1423 var.vt = VT_EMPTY;
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);
1433 return S_OK;
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);
1457 return S_OK;
1460 static BOOL WINAPI media_engine_GetMuted(IMFMediaEngine *iface)
1462 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1463 BOOL ret;
1465 TRACE("%p.\n", iface);
1467 EnterCriticalSection(&engine->cs);
1468 ret = !!(engine->flags & FLAGS_ENGINE_MUTED);
1469 LeaveCriticalSection(&engine->cs);
1471 return ret;
1474 static HRESULT WINAPI media_engine_SetMuted(IMFMediaEngine *iface, BOOL muted)
1476 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1477 HRESULT hr = S_OK;
1479 TRACE("%p, %d.\n", iface, muted);
1481 EnterCriticalSection(&engine->cs);
1482 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1483 hr = MF_E_SHUTDOWN;
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);
1491 return hr;
1494 static double WINAPI media_engine_GetVolume(IMFMediaEngine *iface)
1496 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1497 double volume;
1499 TRACE("%p.\n", iface);
1501 EnterCriticalSection(&engine->cs);
1502 volume = engine->volume;
1503 LeaveCriticalSection(&engine->cs);
1505 return volume;
1508 static HRESULT WINAPI media_engine_SetVolume(IMFMediaEngine *iface, double volume)
1510 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1511 HRESULT hr = S_OK;
1513 TRACE("%p, %f.\n", iface, volume);
1515 EnterCriticalSection(&engine->cs);
1516 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1517 hr = MF_E_SHUTDOWN;
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);
1525 return hr;
1528 static BOOL WINAPI media_engine_HasVideo(IMFMediaEngine *iface)
1530 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1531 BOOL value;
1533 TRACE("%p.\n", iface);
1535 EnterCriticalSection(&engine->cs);
1536 value = !!(engine->flags & FLAGS_ENGINE_HAS_VIDEO);
1537 LeaveCriticalSection(&engine->cs);
1539 return value;
1542 static BOOL WINAPI media_engine_HasAudio(IMFMediaEngine *iface)
1544 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1545 BOOL value;
1547 TRACE("%p.\n", iface);
1549 EnterCriticalSection(&engine->cs);
1550 value = !!(engine->flags & FLAGS_ENGINE_HAS_AUDIO);
1551 LeaveCriticalSection(&engine->cs);
1553 return value;
1556 static HRESULT WINAPI media_engine_GetNativeVideoSize(IMFMediaEngine *iface, DWORD *cx, DWORD *cy)
1558 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1559 HRESULT hr = S_OK;
1561 TRACE("%p, %p, %p.\n", iface, cx, cy);
1563 if (!cx && !cy)
1564 return E_INVALIDARG;
1566 EnterCriticalSection(&engine->cs);
1568 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1569 hr = MF_E_SHUTDOWN;
1570 else if (!engine->video_frame.size.cx && !engine->video_frame.size.cy)
1571 hr = E_FAIL;
1572 else
1574 if (cx) *cx = engine->video_frame.size.cx;
1575 if (cy) *cy = engine->video_frame.size.cy;
1578 LeaveCriticalSection(&engine->cs);
1580 return hr;
1583 static HRESULT WINAPI media_engine_GetVideoAspectRatio(IMFMediaEngine *iface, DWORD *cx, DWORD *cy)
1585 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1586 HRESULT hr = S_OK;
1588 TRACE("%p, %p, %p.\n", iface, cx, cy);
1590 if (!cx && !cy)
1591 return E_INVALIDARG;
1593 EnterCriticalSection(&engine->cs);
1595 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1596 hr = MF_E_SHUTDOWN;
1597 else if (!engine->video_frame.size.cx && !engine->video_frame.size.cy)
1598 hr = E_FAIL;
1599 else
1601 if (cx) *cx = engine->video_frame.ratio.cx;
1602 if (cy) *cy = engine->video_frame.ratio.cy;
1605 LeaveCriticalSection(&engine->cs);
1607 return hr;
1610 static HRESULT WINAPI media_engine_Shutdown(IMFMediaEngine *iface)
1612 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1613 HRESULT hr = S_OK;
1615 FIXME("(%p): stub.\n", iface);
1617 EnterCriticalSection(&engine->cs);
1618 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1619 hr = MF_E_SHUTDOWN;
1620 else
1622 media_engine_set_flag(engine, FLAGS_ENGINE_SHUT_DOWN, TRUE);
1623 IMFMediaSession_Shutdown(engine->session);
1625 LeaveCriticalSection(&engine->cs);
1627 return hr;
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);
1636 return E_NOTIMPL;
1639 static HRESULT WINAPI media_engine_OnVideoStreamTick(IMFMediaEngine *iface, LONGLONG *pts)
1641 struct media_engine *engine = impl_from_IMFMediaEngine(iface);
1642 HRESULT hr;
1644 TRACE("%p, %p.\n", iface, pts);
1646 EnterCriticalSection(&engine->cs);
1648 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1649 hr = MF_E_SHUTDOWN;
1650 else if (!pts)
1651 hr = E_POINTER;
1652 else
1654 *pts = engine->video_frame.pts;
1655 hr = *pts == MINLONGLONG ? S_FALSE : S_OK;
1658 LeaveCriticalSection(&engine->cs);
1660 return hr;
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,
1677 media_engine_Load,
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,
1697 media_engine_Play,
1698 media_engine_Pause,
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))
1718 *obj = iface;
1719 IMFSampleGrabberSinkCallback_AddRef(iface);
1720 return S_OK;
1723 *obj = NULL;
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)
1742 return S_OK;
1745 static HRESULT WINAPI media_engine_grabber_callback_OnClockStop(IMFSampleGrabberSinkCallback *iface,
1746 MFTIME systime)
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);
1755 return S_OK;
1758 static HRESULT WINAPI media_engine_grabber_callback_OnClockPause(IMFSampleGrabberSinkCallback *iface,
1759 MFTIME systime)
1761 return S_OK;
1764 static HRESULT WINAPI media_engine_grabber_callback_OnClockRestart(IMFSampleGrabberSinkCallback *iface,
1765 MFTIME systime)
1767 return S_OK;
1770 static HRESULT WINAPI media_engine_grabber_callback_OnClockSetRate(IMFSampleGrabberSinkCallback *iface,
1771 MFTIME systime, float rate)
1773 return S_OK;
1776 static HRESULT WINAPI media_engine_grabber_callback_OnSetPresentationClock(IMFSampleGrabberSinkCallback *iface,
1777 IMFPresentationClock *clock)
1779 return S_OK;
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);
1799 return S_OK;
1802 static HRESULT WINAPI media_engine_grabber_callback_OnShutdown(IMFSampleGrabberSinkCallback *iface)
1804 return S_OK;
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))
1827 *obj = iface;
1828 IMFMediaEngineClassFactory_AddRef(iface);
1829 return S_OK;
1832 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1833 *obj = NULL;
1834 return E_NOINTERFACE;
1837 static ULONG WINAPI media_engine_factory_AddRef(IMFMediaEngineClassFactory *iface)
1839 return 2;
1842 static ULONG WINAPI media_engine_factory_Release(IMFMediaEngineClassFactory *iface)
1844 return 1;
1847 static HRESULT init_media_engine(DWORD flags, IMFAttributes *attributes, struct media_engine *engine)
1849 DXGI_FORMAT output_format;
1850 UINT64 playback_hwnd;
1851 IMFClock *clock;
1852 HRESULT hr;
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);
1869 if (FAILED(hr))
1870 return hr;
1872 if (FAILED(hr = MFCreateMediaSession(NULL, &engine->session)))
1873 return hr;
1875 if (FAILED(hr = IMFMediaSession_GetClock(engine->session, &clock)))
1876 return hr;
1878 hr = IMFClock_QueryInterface(clock, &IID_IMFPresentationClock, (void **)&engine->clock);
1879 IMFClock_Release(clock);
1880 if (FAILED(hr))
1881 return hr;
1883 if (FAILED(hr = IMFMediaSession_BeginGetEvent(engine->session, &engine->session_events, NULL)))
1884 return hr;
1886 if (FAILED(hr = MFCreateSourceResolver(&engine->resolver)))
1887 return hr;
1889 if (FAILED(hr = MFCreateAttributes(&engine->attributes, 0)))
1890 return hr;
1892 if (FAILED(hr = IMFAttributes_CopyAllItems(attributes, engine->attributes)))
1893 return hr;
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;
1899 else
1901 if (SUCCEEDED(hr))
1902 engine->mode = MEDIA_ENGINE_FRAME_SERVER_MODE;
1903 else
1904 engine->mode = MEDIA_ENGINE_AUDIO_MODE;
1907 return S_OK;
1910 static HRESULT WINAPI media_engine_factory_CreateInstance(IMFMediaEngineClassFactory *iface, DWORD flags,
1911 IMFAttributes *attributes, IMFMediaEngine **engine)
1913 struct media_engine *object;
1914 HRESULT hr;
1916 TRACE("%p, %#x, %p, %p.\n", iface, flags, attributes, engine);
1918 if (!attributes || !engine)
1919 return E_POINTER;
1921 object = calloc(1, sizeof(*object));
1922 if (!object)
1923 return E_OUTOFMEMORY;
1925 hr = init_media_engine(flags, attributes, object);
1926 if (FAILED(hr))
1928 free_media_engine(object);
1929 return hr;
1932 *engine = &object->IMFMediaEngine_iface;
1934 return S_OK;
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);
1972 *obj = iface;
1973 return S_OK;
1976 WARN("interface %s not implemented.\n", debugstr_guid(riid));
1977 *obj = NULL;
1978 return E_NOINTERFACE;
1981 static ULONG WINAPI classfactory_AddRef(IClassFactory *iface)
1983 return 2;
1986 static ULONG WINAPI classfactory_Release(IClassFactory *iface)
1988 return 1;
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);
1995 *obj = NULL;
1997 if (outer)
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);
2006 return S_OK;
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));
2028 *obj = NULL;
2029 return CLASS_E_CLASSNOTAVAILABLE;
2032 HRESULT WINAPI DllCanUnloadNow(void)
2034 return S_FALSE;