[v2 PATCH 2/4] mfmediaengine: Add a stub video renderer.
Nikolay Sivov
nsivov at codeweavers.com
Mon Nov 2 06:54:19 CST 2020
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/mfmediaengine/Makefile.in | 3 +-
dlls/mfmediaengine/main.c | 51 +-
dlls/mfmediaengine/mfmediaengine_private.h | 19 +
dlls/mfmediaengine/renderer.c | 661 +++++++++++++++++++++
4 files changed, 720 insertions(+), 14 deletions(-)
create mode 100644 dlls/mfmediaengine/mfmediaengine_private.h
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/mfmediaengine_private.h b/dlls/mfmediaengine/mfmediaengine_private.h
new file mode 100644
index 00000000000..ab157f3da40
--- /dev/null
+++ b/dlls/mfmediaengine/mfmediaengine_private.h
@@ -0,0 +1,19 @@
+/*
+ * 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
+ */
+
+HRESULT media_engine_create_video_renderer(IMFTopologyNode **node) DECLSPEC_HIDDEN;
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;
+}
--
2.28.0
More information about the wine-devel
mailing list