[PATCH 2/4] mfmediaengine: Add a stub video renderer.

Nikolay Sivov nsivov at codeweavers.com
Mon Nov 2 06:41:16 CST 2020


Signed-off-by: Nikolay Sivov <nsivov at 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;
+}
-- 
2.28.0




More information about the wine-devel mailing list