Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfmediaengine/Makefile.in | 3 +- dlls/mfmediaengine/main.c | 51 ++- dlls/mfmediaengine/renderer.c | 661 +++++++++++++++++++++++++++++++++ 3 files changed, 701 insertions(+), 14 deletions(-) create mode 100644 dlls/mfmediaengine/renderer.c
diff --git a/dlls/mfmediaengine/Makefile.in b/dlls/mfmediaengine/Makefile.in index b97e9eec331..a405b29f92f 100644 --- a/dlls/mfmediaengine/Makefile.in +++ b/dlls/mfmediaengine/Makefile.in @@ -5,7 +5,8 @@ IMPORTS = oleaut32 mfplat mf mfuuid uuid EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ - main.c + main.c \ + renderer.c
IDL_SRCS = \ mediaengine.idl \ diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 64f0ae6d2a1..4b08b3614f4 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -29,6 +29,8 @@ #include "mferror.h" #include "dxgi.h"
+#include "mfmediaengine_private.h" + #include "wine/debug.h" #include "wine/heap.h"
@@ -455,31 +457,54 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi
IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDDATA, 0, 0);
- /* TODO: set up video stream nodes */ - if (SUCCEEDED(hr = MFCreateTopology(&topology))) { - IMFTopologyNode *sar_node = NULL, *audio_src = NULL; + IMFTopologyNode *output_node, *source_node;
if (sd_audio) { - if (FAILED(hr = media_engine_create_source_node(source, pd, sd_audio, &audio_src))) + output_node = source_node = NULL; + + if (FAILED(hr = media_engine_create_source_node(source, pd, sd_audio, &source_node))) WARN("Failed to create audio source node, hr %#x.\n", hr);
- if (FAILED(hr = media_engine_create_audio_renderer(engine, &sar_node))) + if (FAILED(hr = media_engine_create_audio_renderer(engine, &output_node))) WARN("Failed to create audio renderer node, hr %#x.\n", hr);
- if (sar_node && audio_src) + if (output_node && source_node) + { + IMFTopology_AddNode(topology, source_node); + IMFTopology_AddNode(topology, output_node); + IMFTopologyNode_ConnectOutput(source_node, 0, output_node, 0); + } + + if (output_node) + IMFTopologyNode_Release(output_node); + if (source_node) + IMFTopologyNode_Release(source_node); + } + + if (SUCCEEDED(hr) && sd_video) + { + output_node = source_node = NULL; + + if (FAILED(hr = media_engine_create_source_node(source, pd, sd_video, &source_node))) + WARN("Failed to create video source node, hr %#x.\n", hr); + + if (FAILED(hr = media_engine_create_video_renderer(&output_node))) + WARN("Failed to create video renderer node, hr %#x.\n", hr); + + if (output_node && source_node) { - IMFTopology_AddNode(topology, audio_src); - IMFTopology_AddNode(topology, sar_node); - IMFTopologyNode_ConnectOutput(audio_src, 0, sar_node, 0); + IMFTopology_AddNode(topology, source_node); + IMFTopology_AddNode(topology, output_node); + IMFTopologyNode_ConnectOutput(source_node, 0, output_node, 0); }
- if (sar_node) - IMFTopologyNode_Release(sar_node); - if (audio_src) - IMFTopologyNode_Release(audio_src); + if (output_node) + IMFTopologyNode_Release(output_node); + if (source_node) + IMFTopologyNode_Release(source_node); } }
diff --git a/dlls/mfmediaengine/renderer.c b/dlls/mfmediaengine/renderer.c new file mode 100644 index 00000000000..98807f23d0f --- /dev/null +++ b/dlls/mfmediaengine/renderer.c @@ -0,0 +1,661 @@ +/* + * Copyright 2020 Nikolay Sivov for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include "mfapi.h" +#include "mfidl.h" +#include "mferror.h" + +#include "mfmediaengine_private.h" + +#include "wine/debug.h" +#include "wine/heap.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +enum video_renderer_flags +{ + FLAG_SHUT_DOWN = 0x1, +}; + +struct video_renderer +{ + IMFMediaSink IMFMediaSink_iface; + IMFStreamSink IMFStreamSink_iface; + IMFMediaTypeHandler IMFMediaTypeHandler_iface; + IMFMediaEventGenerator IMFMediaEventGenerator_iface; + LONG refcount; + IMFMediaEventQueue *event_queue; + IMFMediaEventQueue *stream_event_queue; + unsigned int flags; + CRITICAL_SECTION cs; +}; + +static struct video_renderer *impl_from_IMFMediaSink(IMFMediaSink *iface) +{ + return CONTAINING_RECORD(iface, struct video_renderer, IMFMediaSink_iface); +} + +static struct video_renderer *impl_from_IMFStreamSink(IMFStreamSink *iface) +{ + return CONTAINING_RECORD(iface, struct video_renderer, IMFStreamSink_iface); +} + +static struct video_renderer *impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler *iface) +{ + return CONTAINING_RECORD(iface, struct video_renderer, IMFMediaEventGenerator_iface); +} + +static struct video_renderer *impl_from_IMFMediaEventGenerator(IMFMediaEventGenerator *iface) +{ + return CONTAINING_RECORD(iface, struct video_renderer, IMFMediaEventGenerator_iface); +} + +static HRESULT WINAPI video_renderer_sink_QueryInterface(IMFMediaSink *iface, REFIID riid, void **obj) +{ + struct video_renderer *renderer = impl_from_IMFMediaSink(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFMediaSink) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + } + else if (IsEqualIID(riid, &IID_IMFMediaEventGenerator)) + { + *obj = &renderer->IMFMediaEventGenerator_iface; + } + else + { + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*obj); + + return S_OK; +} + +static ULONG WINAPI video_renderer_sink_AddRef(IMFMediaSink *iface) +{ + struct video_renderer *renderer = impl_from_IMFMediaSink(iface); + ULONG refcount = InterlockedIncrement(&renderer->refcount); + TRACE("%p, refcount %u.\n", iface, refcount); + return refcount; +} + +static ULONG WINAPI video_renderer_sink_Release(IMFMediaSink *iface) +{ + struct video_renderer *renderer = impl_from_IMFMediaSink(iface); + ULONG refcount = InterlockedDecrement(&renderer->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + { + if (renderer->event_queue) + IMFMediaEventQueue_Release(renderer->event_queue); + if (renderer->stream_event_queue) + IMFMediaEventQueue_Release(renderer->stream_event_queue); + DeleteCriticalSection(&renderer->cs); + heap_free(renderer); + } + + return refcount; +} + +static HRESULT WINAPI video_renderer_sink_GetCharacteristics(IMFMediaSink *iface, DWORD *flags) +{ + struct video_renderer *renderer = impl_from_IMFMediaSink(iface); + + TRACE("%p, %p.\n", iface, flags); + + if (renderer->flags & FLAG_SHUT_DOWN) + return MF_E_SHUTDOWN; + + *flags = MEDIASINK_FIXED_STREAMS; + + return S_OK; +} + +static HRESULT WINAPI video_renderer_sink_AddStreamSink(IMFMediaSink *iface, DWORD stream_sink_id, + IMFMediaType *media_type, IMFStreamSink **stream_sink) +{ + struct video_renderer *renderer = impl_from_IMFMediaSink(iface); + + TRACE("%p, %#x, %p, %p.\n", iface, stream_sink_id, media_type, stream_sink); + + return renderer->flags & FLAG_SHUT_DOWN ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED; +} + +static HRESULT WINAPI video_renderer_sink_RemoveStreamSink(IMFMediaSink *iface, DWORD stream_sink_id) +{ + struct video_renderer *renderer = impl_from_IMFMediaSink(iface); + + TRACE("%p, %#x.\n", iface, stream_sink_id); + + return renderer->flags & FLAG_SHUT_DOWN ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED; +} + +static HRESULT WINAPI video_renderer_sink_GetStreamSinkCount(IMFMediaSink *iface, DWORD *count) +{ + struct video_renderer *renderer = impl_from_IMFMediaSink(iface); + + TRACE("%p, %p.\n", iface, count); + + if (!count) + return E_POINTER; + + if (renderer->flags & FLAG_SHUT_DOWN) + return MF_E_SHUTDOWN; + + *count = 1; + + return S_OK; +} + +static HRESULT WINAPI video_renderer_sink_GetStreamSinkByIndex(IMFMediaSink *iface, DWORD index, + IMFStreamSink **stream) +{ + struct video_renderer *renderer = impl_from_IMFMediaSink(iface); + HRESULT hr = S_OK; + + TRACE("%p, %u, %p.\n", iface, index, stream); + + EnterCriticalSection(&renderer->cs); + + if (renderer->flags & FLAG_SHUT_DOWN) + hr = MF_E_SHUTDOWN; + else if (index > 0) + hr = MF_E_INVALIDINDEX; + else + { + *stream = &renderer->IMFStreamSink_iface; + IMFStreamSink_AddRef(*stream); + } + + LeaveCriticalSection(&renderer->cs); + + return hr; +} + +static HRESULT WINAPI video_renderer_sink_GetStreamSinkById(IMFMediaSink *iface, DWORD stream_sink_id, + IMFStreamSink **stream) +{ + struct video_renderer *renderer = impl_from_IMFMediaSink(iface); + HRESULT hr = S_OK; + + TRACE("%p, %#x, %p.\n", iface, stream_sink_id, stream); + + EnterCriticalSection(&renderer->cs); + + if (renderer->flags & FLAG_SHUT_DOWN) + hr = MF_E_SHUTDOWN; + else if (stream_sink_id > 0) + hr = MF_E_INVALIDSTREAMNUMBER; + else + { + *stream = &renderer->IMFStreamSink_iface; + IMFStreamSink_AddRef(*stream); + } + + LeaveCriticalSection(&renderer->cs); + + return hr; +} + +static HRESULT WINAPI video_renderer_sink_SetPresentationClock(IMFMediaSink *iface, IMFPresentationClock *clock) +{ + FIXME("%p, %p.\n", iface, clock); + + return E_NOTIMPL; +} + +static HRESULT WINAPI video_renderer_sink_GetPresentationClock(IMFMediaSink *iface, + IMFPresentationClock **clock) +{ + FIXME("%p, %p.\n", iface, clock); + + return E_NOTIMPL; +} + +static HRESULT WINAPI video_renderer_sink_Shutdown(IMFMediaSink *iface) +{ + struct video_renderer *renderer = impl_from_IMFMediaSink(iface); + + TRACE("%p.\n", iface); + + if (renderer->flags & FLAG_SHUT_DOWN) + return MF_E_SHUTDOWN; + + EnterCriticalSection(&renderer->cs); + renderer->flags |= FLAG_SHUT_DOWN; + IMFMediaEventQueue_Shutdown(renderer->event_queue); + IMFMediaEventQueue_Shutdown(renderer->stream_event_queue); + LeaveCriticalSection(&renderer->cs); + + return S_OK; +} + +static const IMFMediaSinkVtbl video_renderer_sink_vtbl = +{ + video_renderer_sink_QueryInterface, + video_renderer_sink_AddRef, + video_renderer_sink_Release, + video_renderer_sink_GetCharacteristics, + video_renderer_sink_AddStreamSink, + video_renderer_sink_RemoveStreamSink, + video_renderer_sink_GetStreamSinkCount, + video_renderer_sink_GetStreamSinkByIndex, + video_renderer_sink_GetStreamSinkById, + video_renderer_sink_SetPresentationClock, + video_renderer_sink_GetPresentationClock, + video_renderer_sink_Shutdown, +}; + +static HRESULT WINAPI video_renderer_stream_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj) +{ + struct video_renderer *renderer = impl_from_IMFStreamSink(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFStreamSink) || + IsEqualIID(riid, &IID_IMFMediaEventGenerator) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = &renderer->IMFStreamSink_iface; + } + else if (IsEqualIID(riid, &IID_IMFMediaTypeHandler)) + { + *obj = &renderer->IMFMediaTypeHandler_iface; + } + else + { + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*obj); + + return S_OK; +} + +static ULONG WINAPI video_renderer_stream_AddRef(IMFStreamSink *iface) +{ + struct video_renderer *renderer = impl_from_IMFStreamSink(iface); + return IMFMediaSink_AddRef(&renderer->IMFMediaSink_iface); +} + +static ULONG WINAPI video_renderer_stream_Release(IMFStreamSink *iface) +{ + struct video_renderer *renderer = impl_from_IMFStreamSink(iface); + return IMFMediaSink_Release(&renderer->IMFMediaSink_iface); +} + +static HRESULT WINAPI video_renderer_stream_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event) +{ + struct video_renderer *renderer = impl_from_IMFStreamSink(iface); + + TRACE("%p, %#x, %p.\n", iface, flags, event); + + if (renderer->flags & FLAG_SHUT_DOWN) + return MF_E_STREAMSINK_REMOVED; + + return IMFMediaEventQueue_GetEvent(renderer->stream_event_queue, flags, event); +} + +static HRESULT WINAPI video_renderer_stream_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback, + IUnknown *state) +{ + struct video_renderer *renderer = impl_from_IMFStreamSink(iface); + + TRACE("%p, %p, %p.\n", iface, callback, state); + + if (renderer->flags & FLAG_SHUT_DOWN) + return MF_E_STREAMSINK_REMOVED; + + return IMFMediaEventQueue_BeginGetEvent(renderer->stream_event_queue, callback, state); +} + +static HRESULT WINAPI video_renderer_stream_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result, + IMFMediaEvent **event) +{ + struct video_renderer *renderer = impl_from_IMFStreamSink(iface); + + TRACE("%p, %p, %p.\n", iface, result, event); + + if (renderer->flags & FLAG_SHUT_DOWN) + return MF_E_STREAMSINK_REMOVED; + + return IMFMediaEventQueue_EndGetEvent(renderer->stream_event_queue, result, event); +} + +static HRESULT WINAPI video_renderer_stream_QueueEvent(IMFStreamSink *iface, MediaEventType event_type, + REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) +{ + struct video_renderer *renderer = impl_from_IMFStreamSink(iface); + + TRACE("%p, %u, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value); + + if (renderer->flags & FLAG_SHUT_DOWN) + return MF_E_STREAMSINK_REMOVED; + + return IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, event_type, ext_type, hr, value); +} + +static HRESULT WINAPI video_renderer_stream_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **sink) +{ + struct video_renderer *renderer = impl_from_IMFStreamSink(iface); + + TRACE("%p, %p.\n", iface, sink); + + if (renderer->flags & FLAG_SHUT_DOWN) + return MF_E_STREAMSINK_REMOVED; + + *sink = &renderer->IMFMediaSink_iface; + IMFMediaSink_AddRef(*sink); + + return S_OK; +} + +static HRESULT WINAPI video_renderer_stream_GetIdentifier(IMFStreamSink *iface, DWORD *identifier) +{ + struct video_renderer *renderer = impl_from_IMFStreamSink(iface); + + TRACE("%p, %p.\n", iface, identifier); + + if (renderer->flags & FLAG_SHUT_DOWN) + return MF_E_STREAMSINK_REMOVED; + + *identifier = 0; + + return S_OK; +} + +static HRESULT WINAPI video_renderer_stream_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler) +{ + struct video_renderer *renderer = impl_from_IMFStreamSink(iface); + + TRACE("%p, %p.\n", iface, handler); + + if (!handler) + return E_POINTER; + + if (renderer->flags & FLAG_SHUT_DOWN) + return MF_E_STREAMSINK_REMOVED; + + *handler = &renderer->IMFMediaTypeHandler_iface; + IMFMediaTypeHandler_AddRef(*handler); + + return S_OK; +} + +static HRESULT WINAPI video_renderer_stream_ProcessSample(IMFStreamSink *iface, IMFSample *sample) +{ + struct video_renderer *renderer = impl_from_IMFStreamSink(iface); + + TRACE("%p, %p.\n", iface, sample); + + if (!sample) + return E_POINTER; + + if (renderer->flags & FLAG_SHUT_DOWN) + return MF_E_STREAMSINK_REMOVED; + + /* FIXME: samples are dropped */ + + return S_OK; +} + +static HRESULT WINAPI video_renderer_stream_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type, + const PROPVARIANT *marker_value, const PROPVARIANT *context_value) +{ + struct video_renderer *renderer = impl_from_IMFStreamSink(iface); + + TRACE("%p, %d, %p, %p.\n", iface, marker_type, marker_value, context_value); + + if (renderer->flags & FLAG_SHUT_DOWN) + return MF_E_STREAMSINK_REMOVED; + + return S_OK; +} + +static HRESULT WINAPI video_renderer_stream_Flush(IMFStreamSink *iface) +{ + struct video_renderer *renderer = impl_from_IMFStreamSink(iface); + + TRACE("%p.\n", iface); + + if (renderer->flags & FLAG_SHUT_DOWN) + return MF_E_STREAMSINK_REMOVED; + + return S_OK; +} + +static const IMFStreamSinkVtbl video_renderer_stream_vtbl = +{ + video_renderer_stream_QueryInterface, + video_renderer_stream_AddRef, + video_renderer_stream_Release, + video_renderer_stream_GetEvent, + video_renderer_stream_BeginGetEvent, + video_renderer_stream_EndGetEvent, + video_renderer_stream_QueueEvent, + video_renderer_stream_GetMediaSink, + video_renderer_stream_GetIdentifier, + video_renderer_stream_GetMediaTypeHandler, + video_renderer_stream_ProcessSample, + video_renderer_stream_PlaceMarker, + video_renderer_stream_Flush, +}; + +static HRESULT WINAPI video_renderer_stream_type_handler_QueryInterface(IMFMediaTypeHandler *iface, REFIID riid, + void **obj) +{ + struct video_renderer *renderer = impl_from_IMFMediaTypeHandler(iface); + return IMFStreamSink_QueryInterface(&renderer->IMFStreamSink_iface, riid, obj); +} + +static ULONG WINAPI video_renderer_stream_type_handler_AddRef(IMFMediaTypeHandler *iface) +{ + struct video_renderer *renderer = impl_from_IMFMediaTypeHandler(iface); + return IMFStreamSink_AddRef(&renderer->IMFStreamSink_iface); +} + +static ULONG WINAPI video_renderer_stream_type_handler_Release(IMFMediaTypeHandler *iface) +{ + struct video_renderer *renderer = impl_from_IMFMediaTypeHandler(iface); + return IMFStreamSink_Release(&renderer->IMFStreamSink_iface); +} + +static HRESULT WINAPI video_renderer_stream_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler *iface, + IMFMediaType *in_type, IMFMediaType **out_type) +{ + FIXME("%p, %p, %p.\n", iface, in_type, out_type); + + return S_OK; +} + +static HRESULT WINAPI video_renderer_stream_type_handler_GetMediaTypeCount(IMFMediaTypeHandler *iface, DWORD *count) +{ + FIXME("%p, %p.\n", iface, count); + + return E_NOTIMPL; +} + +static HRESULT WINAPI video_renderer_stream_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler *iface, DWORD index, + IMFMediaType **media_type) +{ + FIXME("%p, %u, %p.\n", iface, index, media_type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI video_renderer_stream_type_handler_SetCurrentMediaType(IMFMediaTypeHandler *iface, + IMFMediaType *media_type) +{ + FIXME("%p, %p.\n", iface, media_type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI video_renderer_stream_type_handler_GetCurrentMediaType(IMFMediaTypeHandler *iface, + IMFMediaType **media_type) +{ + FIXME("%p, %p.\n", iface, media_type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI video_renderer_stream_type_handler_GetMajorType(IMFMediaTypeHandler *iface, GUID *type) +{ + struct video_renderer *renderer = impl_from_IMFMediaTypeHandler(iface); + + TRACE("%p, %p.\n", iface, type); + + if (!type) + return E_POINTER; + + if (renderer->flags & FLAG_SHUT_DOWN) + return MF_E_STREAMSINK_REMOVED; + + memcpy(type, &MFMediaType_Video, sizeof(*type)); + return S_OK; +} + +static const IMFMediaTypeHandlerVtbl video_renderer_stream_type_handler_vtbl = +{ + video_renderer_stream_type_handler_QueryInterface, + video_renderer_stream_type_handler_AddRef, + video_renderer_stream_type_handler_Release, + video_renderer_stream_type_handler_IsMediaTypeSupported, + video_renderer_stream_type_handler_GetMediaTypeCount, + video_renderer_stream_type_handler_GetMediaTypeByIndex, + video_renderer_stream_type_handler_SetCurrentMediaType, + video_renderer_stream_type_handler_GetCurrentMediaType, + video_renderer_stream_type_handler_GetMajorType, +}; + +static HRESULT WINAPI video_renderer_events_QueryInterface(IMFMediaEventGenerator *iface, + REFIID riid, void **obj) +{ + struct video_renderer *renderer = impl_from_IMFMediaEventGenerator(iface); + return IMFMediaSink_QueryInterface(&renderer->IMFMediaSink_iface, riid, obj); +} + +static ULONG WINAPI video_renderer_events_AddRef(IMFMediaEventGenerator *iface) +{ + struct video_renderer *renderer = impl_from_IMFMediaEventGenerator(iface); + return IMFMediaSink_AddRef(&renderer->IMFMediaSink_iface); +} + +static ULONG WINAPI video_renderer_events_Release(IMFMediaEventGenerator *iface) +{ + struct video_renderer *renderer = impl_from_IMFMediaEventGenerator(iface); + return IMFMediaSink_Release(&renderer->IMFMediaSink_iface); +} + +static HRESULT WINAPI video_renderer_events_GetEvent(IMFMediaEventGenerator *iface, DWORD flags, IMFMediaEvent **event) +{ + struct video_renderer *renderer = impl_from_IMFMediaEventGenerator(iface); + + TRACE("%p, %#x, %p.\n", iface, flags, event); + + return IMFMediaEventQueue_GetEvent(renderer->event_queue, flags, event); +} + +static HRESULT WINAPI video_renderer_events_BeginGetEvent(IMFMediaEventGenerator *iface, IMFAsyncCallback *callback, + IUnknown *state) +{ + struct video_renderer *renderer = impl_from_IMFMediaEventGenerator(iface); + + TRACE("%p, %p, %p.\n", iface, callback, state); + + return IMFMediaEventQueue_BeginGetEvent(renderer->event_queue, callback, state); +} + +static HRESULT WINAPI video_renderer_events_EndGetEvent(IMFMediaEventGenerator *iface, IMFAsyncResult *result, + IMFMediaEvent **event) +{ + struct video_renderer *renderer = impl_from_IMFMediaEventGenerator(iface); + + TRACE("%p, %p, %p.\n", iface, result, event); + + return IMFMediaEventQueue_EndGetEvent(renderer->event_queue, result, event); +} + +static HRESULT WINAPI video_renderer_events_QueueEvent(IMFMediaEventGenerator *iface, MediaEventType event_type, + REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) +{ + struct video_renderer *renderer = impl_from_IMFMediaEventGenerator(iface); + + TRACE("%p, %u, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value); + + return IMFMediaEventQueue_QueueEventParamVar(renderer->event_queue, event_type, ext_type, hr, value); +} + +static const IMFMediaEventGeneratorVtbl video_renderer_events_vtbl = +{ + video_renderer_events_QueryInterface, + video_renderer_events_AddRef, + video_renderer_events_Release, + video_renderer_events_GetEvent, + video_renderer_events_BeginGetEvent, + video_renderer_events_EndGetEvent, + video_renderer_events_QueueEvent, +}; + +HRESULT media_engine_create_video_renderer(IMFTopologyNode **node) +{ + struct video_renderer *renderer; + HRESULT hr; + + *node = NULL; + + if (!(renderer = heap_alloc_zero(sizeof(*renderer)))) + return E_OUTOFMEMORY; + + renderer->IMFMediaSink_iface.lpVtbl = &video_renderer_sink_vtbl; + renderer->IMFStreamSink_iface.lpVtbl = &video_renderer_stream_vtbl; + renderer->IMFMediaTypeHandler_iface.lpVtbl = &video_renderer_stream_type_handler_vtbl; + renderer->IMFMediaEventGenerator_iface.lpVtbl = &video_renderer_events_vtbl; + renderer->refcount = 1; + InitializeCriticalSection(&renderer->cs); + + if (FAILED(hr = MFCreateEventQueue(&renderer->event_queue))) + goto failed; + + if (FAILED(hr = MFCreateEventQueue(&renderer->stream_event_queue))) + goto failed; + + if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, node))) + goto failed; + + IMFTopologyNode_SetObject(*node, (IUnknown *)&renderer->IMFStreamSink_iface); + IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE); + +failed: + + IMFMediaSink_Release(&renderer->IMFMediaSink_iface); + + return hr; +}