Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
November 2020
- 73 participants
- 1459 messages
[PATCH 1/2 v4] msvcrt: Fix scanf with dashes in scanset.
by Piotr Caban
From: Will Mainio <will.mainio(a)fastmail.com>
Signed-off-by: Will Mainio <will.mainio(a)fastmail.com>
Signed-off-by: Piotr Caban <piotr(a)codeweavers.com>
---
dlls/msvcrt/scanf.h | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
Nov. 2, 2020
[v2 PATCH 4/4] mfmediaengine/renderer: Request more samples when in running state.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mfmediaengine/renderer.c | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/dlls/mfmediaengine/renderer.c b/dlls/mfmediaengine/renderer.c
index d747f42774a..0d558e16963 100644
--- a/dlls/mfmediaengine/renderer.c
+++ b/dlls/mfmediaengine/renderer.c
@@ -513,6 +513,13 @@ static HRESULT WINAPI video_renderer_stream_ProcessSample(IMFStreamSink *iface,
/* FIXME: samples are dropped */
+ EnterCriticalSection(&renderer->cs);
+
+ if (renderer->state == STREAM_STATE_RUNNING)
+ IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkRequestSample, &GUID_NULL, S_OK, NULL);
+
+ LeaveCriticalSection(&renderer->cs);
+
return S_OK;
}
@@ -741,9 +748,12 @@ static HRESULT WINAPI video_renderer_clock_sink_OnClockStart(IMFClockStateSink *
EnterCriticalSection(&renderer->cs);
if (renderer->state == STREAM_STATE_STOPPED)
- renderer->state = STREAM_STATE_RUNNING;
+ {
+ IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStarted, &GUID_NULL, S_OK, NULL);
+ IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkRequestSample, &GUID_NULL, S_OK, NULL);
- IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStarted, &GUID_NULL, S_OK, NULL);
+ renderer->state = STREAM_STATE_RUNNING;
+ }
LeaveCriticalSection(&renderer->cs);
@@ -796,7 +806,13 @@ static HRESULT WINAPI video_renderer_clock_sink_OnClockRestart(IMFClockStateSink
EnterCriticalSection(&renderer->cs);
- IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStarted, &GUID_NULL, S_OK, NULL);
+ if (renderer->state != STREAM_STATE_RUNNING)
+ {
+ IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStarted, &GUID_NULL, S_OK, NULL);
+ IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkRequestSample, &GUID_NULL, S_OK, NULL);
+
+ renderer->state = STREAM_STATE_RUNNING;
+ }
LeaveCriticalSection(&renderer->cs);
--
2.28.0
Nov. 2, 2020
[v2 PATCH 3/4] mfmediaengine/renderer: Add clock state sink.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mfmediaengine/renderer.c | 207 +++++++++++++++++++++++++++++++++-
1 file changed, 203 insertions(+), 4 deletions(-)
diff --git a/dlls/mfmediaengine/renderer.c b/dlls/mfmediaengine/renderer.c
index 98807f23d0f..d747f42774a 100644
--- a/dlls/mfmediaengine/renderer.c
+++ b/dlls/mfmediaengine/renderer.c
@@ -29,6 +29,34 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+static const char *debugstr_time(LONGLONG time)
+{
+ ULONGLONG abstime = time >= 0 ? time : -time;
+ unsigned int i = 0, j = 0;
+ char buffer[23], rev[23];
+
+ while (abstime || i <= 8)
+ {
+ buffer[i++] = '0' + (abstime % 10);
+ abstime /= 10;
+ if (i == 7) buffer[i++] = '.';
+ }
+ if (time < 0) buffer[i++] = '-';
+
+ while (i--) rev[j++] = buffer[i];
+ while (rev[j-1] == '0' && rev[j-2] != '.') --j;
+ rev[j] = 0;
+
+ return wine_dbg_sprintf("%s", rev);
+}
+
+enum stream_state
+{
+ STREAM_STATE_STOPPED = 0,
+ STREAM_STATE_RUNNING,
+ STREAM_STATE_PAUSED,
+};
+
enum video_renderer_flags
{
FLAG_SHUT_DOWN = 0x1,
@@ -39,11 +67,14 @@ struct video_renderer
IMFMediaSink IMFMediaSink_iface;
IMFStreamSink IMFStreamSink_iface;
IMFMediaTypeHandler IMFMediaTypeHandler_iface;
+ IMFClockStateSink IMFClockStateSink_iface;
IMFMediaEventGenerator IMFMediaEventGenerator_iface;
LONG refcount;
IMFMediaEventQueue *event_queue;
IMFMediaEventQueue *stream_event_queue;
+ IMFPresentationClock *clock;
unsigned int flags;
+ unsigned int state;
CRITICAL_SECTION cs;
};
@@ -52,6 +83,11 @@ static struct video_renderer *impl_from_IMFMediaSink(IMFMediaSink *iface)
return CONTAINING_RECORD(iface, struct video_renderer, IMFMediaSink_iface);
}
+static struct video_renderer *impl_from_IMFClockStateSink(IMFClockStateSink *iface)
+{
+ return CONTAINING_RECORD(iface, struct video_renderer, IMFClockStateSink_iface);
+}
+
static struct video_renderer *impl_from_IMFStreamSink(IMFStreamSink *iface)
{
return CONTAINING_RECORD(iface, struct video_renderer, IMFStreamSink_iface);
@@ -78,6 +114,10 @@ static HRESULT WINAPI video_renderer_sink_QueryInterface(IMFMediaSink *iface, RE
{
*obj = iface;
}
+ else if (IsEqualIID(riid, &IID_IMFClockStateSink))
+ {
+ *obj = &renderer->IMFClockStateSink_iface;
+ }
else if (IsEqualIID(riid, &IID_IMFMediaEventGenerator))
{
*obj = &renderer->IMFMediaEventGenerator_iface;
@@ -115,6 +155,8 @@ static ULONG WINAPI video_renderer_sink_Release(IMFMediaSink *iface)
IMFMediaEventQueue_Release(renderer->event_queue);
if (renderer->stream_event_queue)
IMFMediaEventQueue_Release(renderer->stream_event_queue);
+ if (renderer->clock)
+ IMFPresentationClock_Release(renderer->clock);
DeleteCriticalSection(&renderer->cs);
heap_free(renderer);
}
@@ -222,19 +264,66 @@ static HRESULT WINAPI video_renderer_sink_GetStreamSinkById(IMFMediaSink *iface,
return hr;
}
+static void video_renderer_set_presentation_clock(struct video_renderer *renderer, IMFPresentationClock *clock)
+{
+ if (renderer->clock)
+ {
+ IMFPresentationClock_RemoveClockStateSink(renderer->clock, &renderer->IMFClockStateSink_iface);
+ IMFPresentationClock_Release(renderer->clock);
+ }
+ renderer->clock = clock;
+ if (renderer->clock)
+ {
+ IMFPresentationClock_AddRef(renderer->clock);
+ IMFPresentationClock_AddClockStateSink(renderer->clock, &renderer->IMFClockStateSink_iface);
+ }
+}
+
static HRESULT WINAPI video_renderer_sink_SetPresentationClock(IMFMediaSink *iface, IMFPresentationClock *clock)
{
- FIXME("%p, %p.\n", iface, clock);
+ struct video_renderer *renderer = impl_from_IMFMediaSink(iface);
+ HRESULT hr = S_OK;
- return E_NOTIMPL;
+ TRACE("%p, %p.\n", iface, clock);
+
+ EnterCriticalSection(&renderer->cs);
+
+ if (renderer->flags & FLAG_SHUT_DOWN)
+ hr = MF_E_SHUTDOWN;
+ else
+ video_renderer_set_presentation_clock(renderer, clock);
+
+ LeaveCriticalSection(&renderer->cs);
+
+ return hr;
}
static HRESULT WINAPI video_renderer_sink_GetPresentationClock(IMFMediaSink *iface,
IMFPresentationClock **clock)
{
- FIXME("%p, %p.\n", iface, clock);
+ struct video_renderer *renderer = impl_from_IMFMediaSink(iface);
+ HRESULT hr = S_OK;
- return E_NOTIMPL;
+ TRACE("%p, %p.\n", iface, clock);
+
+ if (!clock)
+ return E_POINTER;
+
+ EnterCriticalSection(&renderer->cs);
+
+ if (renderer->flags & FLAG_SHUT_DOWN)
+ hr = MF_E_SHUTDOWN;
+ else if (renderer->clock)
+ {
+ *clock = renderer->clock;
+ IMFPresentationClock_AddRef(*clock);
+ }
+ else
+ hr = MF_E_NO_CLOCK;
+
+ LeaveCriticalSection(&renderer->cs);
+
+ return hr;
}
static HRESULT WINAPI video_renderer_sink_Shutdown(IMFMediaSink *iface)
@@ -250,6 +339,7 @@ static HRESULT WINAPI video_renderer_sink_Shutdown(IMFMediaSink *iface)
renderer->flags |= FLAG_SHUT_DOWN;
IMFMediaEventQueue_Shutdown(renderer->event_queue);
IMFMediaEventQueue_Shutdown(renderer->stream_event_queue);
+ video_renderer_set_presentation_clock(renderer, NULL);
LeaveCriticalSection(&renderer->cs);
return S_OK;
@@ -624,6 +714,114 @@ static const IMFMediaEventGeneratorVtbl video_renderer_events_vtbl =
video_renderer_events_QueueEvent,
};
+static HRESULT WINAPI video_renderer_clock_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj)
+{
+ struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+ return IMFMediaSink_QueryInterface(&renderer->IMFMediaSink_iface, riid, obj);
+}
+
+static ULONG WINAPI video_renderer_clock_sink_AddRef(IMFClockStateSink *iface)
+{
+ struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+ return IMFMediaSink_AddRef(&renderer->IMFMediaSink_iface);
+}
+
+static ULONG WINAPI video_renderer_clock_sink_Release(IMFClockStateSink *iface)
+{
+ struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+ return IMFMediaSink_Release(&renderer->IMFMediaSink_iface);
+}
+
+static HRESULT WINAPI video_renderer_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset)
+{
+ struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+
+ TRACE("%p, %s, %s.\n", iface, debugstr_time(systime), debugstr_time(offset));
+
+ EnterCriticalSection(&renderer->cs);
+
+ if (renderer->state == STREAM_STATE_STOPPED)
+ renderer->state = STREAM_STATE_RUNNING;
+
+ IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStarted, &GUID_NULL, S_OK, NULL);
+
+ LeaveCriticalSection(&renderer->cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI video_renderer_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime)
+{
+ struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+
+ TRACE("%p, %s.\n", iface, debugstr_time(systime));
+
+ EnterCriticalSection(&renderer->cs);
+
+ renderer->state = STREAM_STATE_STOPPED;
+ IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStopped, &GUID_NULL, S_OK, NULL);
+
+ LeaveCriticalSection(&renderer->cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI video_renderer_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime)
+{
+ struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %s.\n", iface, debugstr_time(systime));
+
+ EnterCriticalSection(&renderer->cs);
+
+ if (renderer->state == STREAM_STATE_RUNNING)
+ {
+ renderer->state = STREAM_STATE_PAUSED;
+ IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkPaused, &GUID_NULL, S_OK, NULL);
+ }
+ else
+ hr = MF_E_INVALID_STATE_TRANSITION;
+
+ LeaveCriticalSection(&renderer->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI video_renderer_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime)
+{
+ struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+
+ TRACE("%p, %s.\n", iface, debugstr_time(systime));
+
+ EnterCriticalSection(&renderer->cs);
+
+ IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStarted, &GUID_NULL, S_OK, NULL);
+
+ LeaveCriticalSection(&renderer->cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI video_renderer_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME systime, float rate)
+{
+ FIXME("%p, %s, %f.\n", iface, debugstr_time(systime), rate);
+
+ return E_NOTIMPL;
+}
+
+static const IMFClockStateSinkVtbl video_renderer_clock_sink_vtbl =
+{
+ video_renderer_clock_sink_QueryInterface,
+ video_renderer_clock_sink_AddRef,
+ video_renderer_clock_sink_Release,
+ video_renderer_clock_sink_OnClockStart,
+ video_renderer_clock_sink_OnClockStop,
+ video_renderer_clock_sink_OnClockPause,
+ video_renderer_clock_sink_OnClockRestart,
+ video_renderer_clock_sink_OnClockSetRate,
+};
+
HRESULT media_engine_create_video_renderer(IMFTopologyNode **node)
{
struct video_renderer *renderer;
@@ -638,6 +836,7 @@ HRESULT media_engine_create_video_renderer(IMFTopologyNode **node)
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->IMFClockStateSink_iface.lpVtbl = &video_renderer_clock_sink_vtbl;
renderer->refcount = 1;
InitializeCriticalSection(&renderer->cs);
--
2.28.0
Nov. 2, 2020
[v2 PATCH 2/4] mfmediaengine: Add a stub video renderer.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)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
Nov. 2, 2020
[v2 PATCH 1/4] mfmediaengine: Keep "preload" property.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mfmediaengine/main.c | 22 ++++++++++++++++++----
dlls/mfmediaengine/tests/mfmediaengine.c | 9 ++++++---
2 files changed, 24 insertions(+), 7 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c
index d93e2b2f38c..64f0ae6d2a1 100644
--- a/dlls/mfmediaengine/main.c
+++ b/dlls/mfmediaengine/main.c
@@ -87,6 +87,7 @@ struct media_engine
MF_MEDIA_ENGINE_ERR error_code;
HRESULT extended_code;
MF_MEDIA_ENGINE_READY ready_state;
+ MF_MEDIA_ENGINE_PRELOAD preload;
IMFMediaSession *session;
IMFSourceResolver *resolver;
BSTR current_source;
@@ -717,16 +718,29 @@ static USHORT WINAPI media_engine_GetNetworkState(IMFMediaEngine *iface)
static MF_MEDIA_ENGINE_PRELOAD WINAPI media_engine_GetPreload(IMFMediaEngine *iface)
{
- FIXME("(%p): stub.\n", iface);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
+ MF_MEDIA_ENGINE_PRELOAD preload;
+
+ TRACE("%p.\n", iface);
+
+ EnterCriticalSection(&engine->cs);
+ preload = engine->preload;
+ LeaveCriticalSection(&engine->cs);
- return MF_MEDIA_ENGINE_PRELOAD_NONE;
+ return preload;
}
static HRESULT WINAPI media_engine_SetPreload(IMFMediaEngine *iface, MF_MEDIA_ENGINE_PRELOAD preload)
{
- FIXME("(%p, %d): stub.\n", iface, preload);
+ struct media_engine *engine = impl_from_IMFMediaEngine(iface);
- return E_NOTIMPL;
+ TRACE("%p, %d.\n", iface, preload);
+
+ EnterCriticalSection(&engine->cs);
+ engine->preload = preload;
+ LeaveCriticalSection(&engine->cs);
+
+ return S_OK;
}
static HRESULT WINAPI media_engine_GetBuffered(IMFMediaEngine *iface, IMFMediaTimeRange **buffered)
diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c
index 660e5b95331..0394bcf6a0e 100644
--- a/dlls/mfmediaengine/tests/mfmediaengine.c
+++ b/dlls/mfmediaengine/tests/mfmediaengine.c
@@ -265,17 +265,20 @@ todo_wine
/* Preload mode is still accessible. */
state = IMFMediaEngine_GetPreload(media_engine);
-todo_wine
ok(!state, "Unexpected state %d.\n", state);
hr = IMFMediaEngine_SetPreload(media_engine, MF_MEDIA_ENGINE_PRELOAD_AUTOMATIC);
-todo_wine
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
state = IMFMediaEngine_GetPreload(media_engine);
-todo_wine
ok(state == MF_MEDIA_ENGINE_PRELOAD_AUTOMATIC, "Unexpected state %d.\n", state);
+ hr = IMFMediaEngine_SetPreload(media_engine, 100);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ state = IMFMediaEngine_GetPreload(media_engine);
+ ok(state == 100, "Unexpected state %d.\n", state);
+
hr = IMFMediaEngine_GetBuffered(media_engine, &time_range);
todo_wine
ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
--
2.28.0
Nov. 2, 2020
Re: [PATCH 4/4] mfmediaengine/renderer: Request more samples when in running state.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=81350
Your paranoid android.
=== debiant (build log) ===
../wine/dlls/mfmediaengine/main.c:32: error: mfmediaengine_private.h: No such file or directory
config.status: error: could not create Makefile
Task: The win32 Wine build failed
=== debiant (build log) ===
../wine/dlls/mfmediaengine/main.c:32: error: mfmediaengine_private.h: No such file or directory
config.status: error: could not create Makefile
Task: The wow64 Wine build failed
Nov. 2, 2020
Re: [PATCH 3/4] mfmediaengine/renderer: Add clock state sink.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=81349
Your paranoid android.
=== debiant (build log) ===
../wine/dlls/mfmediaengine/main.c:32: error: mfmediaengine_private.h: No such file or directory
config.status: error: could not create Makefile
Task: The win32 Wine build failed
=== debiant (build log) ===
../wine/dlls/mfmediaengine/main.c:32: error: mfmediaengine_private.h: No such file or directory
config.status: error: could not create Makefile
Task: The wow64 Wine build failed
Nov. 2, 2020
Re: [PATCH 2/4] mfmediaengine: Add a stub video renderer.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=81348
Your paranoid android.
=== debiant (build log) ===
../wine/dlls/mfmediaengine/main.c:32: error: mfmediaengine_private.h: No such file or directory
config.status: error: could not create Makefile
Task: The win32 Wine build failed
=== debiant (build log) ===
../wine/dlls/mfmediaengine/main.c:32: error: mfmediaengine_private.h: No such file or directory
config.status: error: could not create Makefile
Task: The wow64 Wine build failed
Nov. 2, 2020
[PATCH 4/4] mfmediaengine/renderer: Request more samples when in running state.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mfmediaengine/renderer.c | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/dlls/mfmediaengine/renderer.c b/dlls/mfmediaengine/renderer.c
index d747f42774a..0d558e16963 100644
--- a/dlls/mfmediaengine/renderer.c
+++ b/dlls/mfmediaengine/renderer.c
@@ -513,6 +513,13 @@ static HRESULT WINAPI video_renderer_stream_ProcessSample(IMFStreamSink *iface,
/* FIXME: samples are dropped */
+ EnterCriticalSection(&renderer->cs);
+
+ if (renderer->state == STREAM_STATE_RUNNING)
+ IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkRequestSample, &GUID_NULL, S_OK, NULL);
+
+ LeaveCriticalSection(&renderer->cs);
+
return S_OK;
}
@@ -741,9 +748,12 @@ static HRESULT WINAPI video_renderer_clock_sink_OnClockStart(IMFClockStateSink *
EnterCriticalSection(&renderer->cs);
if (renderer->state == STREAM_STATE_STOPPED)
- renderer->state = STREAM_STATE_RUNNING;
+ {
+ IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStarted, &GUID_NULL, S_OK, NULL);
+ IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkRequestSample, &GUID_NULL, S_OK, NULL);
- IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStarted, &GUID_NULL, S_OK, NULL);
+ renderer->state = STREAM_STATE_RUNNING;
+ }
LeaveCriticalSection(&renderer->cs);
@@ -796,7 +806,13 @@ static HRESULT WINAPI video_renderer_clock_sink_OnClockRestart(IMFClockStateSink
EnterCriticalSection(&renderer->cs);
- IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStarted, &GUID_NULL, S_OK, NULL);
+ if (renderer->state != STREAM_STATE_RUNNING)
+ {
+ IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStarted, &GUID_NULL, S_OK, NULL);
+ IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkRequestSample, &GUID_NULL, S_OK, NULL);
+
+ renderer->state = STREAM_STATE_RUNNING;
+ }
LeaveCriticalSection(&renderer->cs);
--
2.28.0
Nov. 2, 2020
[PATCH 3/4] mfmediaengine/renderer: Add clock state sink.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mfmediaengine/renderer.c | 207 +++++++++++++++++++++++++++++++++-
1 file changed, 203 insertions(+), 4 deletions(-)
diff --git a/dlls/mfmediaengine/renderer.c b/dlls/mfmediaengine/renderer.c
index 98807f23d0f..d747f42774a 100644
--- a/dlls/mfmediaengine/renderer.c
+++ b/dlls/mfmediaengine/renderer.c
@@ -29,6 +29,34 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+static const char *debugstr_time(LONGLONG time)
+{
+ ULONGLONG abstime = time >= 0 ? time : -time;
+ unsigned int i = 0, j = 0;
+ char buffer[23], rev[23];
+
+ while (abstime || i <= 8)
+ {
+ buffer[i++] = '0' + (abstime % 10);
+ abstime /= 10;
+ if (i == 7) buffer[i++] = '.';
+ }
+ if (time < 0) buffer[i++] = '-';
+
+ while (i--) rev[j++] = buffer[i];
+ while (rev[j-1] == '0' && rev[j-2] != '.') --j;
+ rev[j] = 0;
+
+ return wine_dbg_sprintf("%s", rev);
+}
+
+enum stream_state
+{
+ STREAM_STATE_STOPPED = 0,
+ STREAM_STATE_RUNNING,
+ STREAM_STATE_PAUSED,
+};
+
enum video_renderer_flags
{
FLAG_SHUT_DOWN = 0x1,
@@ -39,11 +67,14 @@ struct video_renderer
IMFMediaSink IMFMediaSink_iface;
IMFStreamSink IMFStreamSink_iface;
IMFMediaTypeHandler IMFMediaTypeHandler_iface;
+ IMFClockStateSink IMFClockStateSink_iface;
IMFMediaEventGenerator IMFMediaEventGenerator_iface;
LONG refcount;
IMFMediaEventQueue *event_queue;
IMFMediaEventQueue *stream_event_queue;
+ IMFPresentationClock *clock;
unsigned int flags;
+ unsigned int state;
CRITICAL_SECTION cs;
};
@@ -52,6 +83,11 @@ static struct video_renderer *impl_from_IMFMediaSink(IMFMediaSink *iface)
return CONTAINING_RECORD(iface, struct video_renderer, IMFMediaSink_iface);
}
+static struct video_renderer *impl_from_IMFClockStateSink(IMFClockStateSink *iface)
+{
+ return CONTAINING_RECORD(iface, struct video_renderer, IMFClockStateSink_iface);
+}
+
static struct video_renderer *impl_from_IMFStreamSink(IMFStreamSink *iface)
{
return CONTAINING_RECORD(iface, struct video_renderer, IMFStreamSink_iface);
@@ -78,6 +114,10 @@ static HRESULT WINAPI video_renderer_sink_QueryInterface(IMFMediaSink *iface, RE
{
*obj = iface;
}
+ else if (IsEqualIID(riid, &IID_IMFClockStateSink))
+ {
+ *obj = &renderer->IMFClockStateSink_iface;
+ }
else if (IsEqualIID(riid, &IID_IMFMediaEventGenerator))
{
*obj = &renderer->IMFMediaEventGenerator_iface;
@@ -115,6 +155,8 @@ static ULONG WINAPI video_renderer_sink_Release(IMFMediaSink *iface)
IMFMediaEventQueue_Release(renderer->event_queue);
if (renderer->stream_event_queue)
IMFMediaEventQueue_Release(renderer->stream_event_queue);
+ if (renderer->clock)
+ IMFPresentationClock_Release(renderer->clock);
DeleteCriticalSection(&renderer->cs);
heap_free(renderer);
}
@@ -222,19 +264,66 @@ static HRESULT WINAPI video_renderer_sink_GetStreamSinkById(IMFMediaSink *iface,
return hr;
}
+static void video_renderer_set_presentation_clock(struct video_renderer *renderer, IMFPresentationClock *clock)
+{
+ if (renderer->clock)
+ {
+ IMFPresentationClock_RemoveClockStateSink(renderer->clock, &renderer->IMFClockStateSink_iface);
+ IMFPresentationClock_Release(renderer->clock);
+ }
+ renderer->clock = clock;
+ if (renderer->clock)
+ {
+ IMFPresentationClock_AddRef(renderer->clock);
+ IMFPresentationClock_AddClockStateSink(renderer->clock, &renderer->IMFClockStateSink_iface);
+ }
+}
+
static HRESULT WINAPI video_renderer_sink_SetPresentationClock(IMFMediaSink *iface, IMFPresentationClock *clock)
{
- FIXME("%p, %p.\n", iface, clock);
+ struct video_renderer *renderer = impl_from_IMFMediaSink(iface);
+ HRESULT hr = S_OK;
- return E_NOTIMPL;
+ TRACE("%p, %p.\n", iface, clock);
+
+ EnterCriticalSection(&renderer->cs);
+
+ if (renderer->flags & FLAG_SHUT_DOWN)
+ hr = MF_E_SHUTDOWN;
+ else
+ video_renderer_set_presentation_clock(renderer, clock);
+
+ LeaveCriticalSection(&renderer->cs);
+
+ return hr;
}
static HRESULT WINAPI video_renderer_sink_GetPresentationClock(IMFMediaSink *iface,
IMFPresentationClock **clock)
{
- FIXME("%p, %p.\n", iface, clock);
+ struct video_renderer *renderer = impl_from_IMFMediaSink(iface);
+ HRESULT hr = S_OK;
- return E_NOTIMPL;
+ TRACE("%p, %p.\n", iface, clock);
+
+ if (!clock)
+ return E_POINTER;
+
+ EnterCriticalSection(&renderer->cs);
+
+ if (renderer->flags & FLAG_SHUT_DOWN)
+ hr = MF_E_SHUTDOWN;
+ else if (renderer->clock)
+ {
+ *clock = renderer->clock;
+ IMFPresentationClock_AddRef(*clock);
+ }
+ else
+ hr = MF_E_NO_CLOCK;
+
+ LeaveCriticalSection(&renderer->cs);
+
+ return hr;
}
static HRESULT WINAPI video_renderer_sink_Shutdown(IMFMediaSink *iface)
@@ -250,6 +339,7 @@ static HRESULT WINAPI video_renderer_sink_Shutdown(IMFMediaSink *iface)
renderer->flags |= FLAG_SHUT_DOWN;
IMFMediaEventQueue_Shutdown(renderer->event_queue);
IMFMediaEventQueue_Shutdown(renderer->stream_event_queue);
+ video_renderer_set_presentation_clock(renderer, NULL);
LeaveCriticalSection(&renderer->cs);
return S_OK;
@@ -624,6 +714,114 @@ static const IMFMediaEventGeneratorVtbl video_renderer_events_vtbl =
video_renderer_events_QueueEvent,
};
+static HRESULT WINAPI video_renderer_clock_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj)
+{
+ struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+ return IMFMediaSink_QueryInterface(&renderer->IMFMediaSink_iface, riid, obj);
+}
+
+static ULONG WINAPI video_renderer_clock_sink_AddRef(IMFClockStateSink *iface)
+{
+ struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+ return IMFMediaSink_AddRef(&renderer->IMFMediaSink_iface);
+}
+
+static ULONG WINAPI video_renderer_clock_sink_Release(IMFClockStateSink *iface)
+{
+ struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+ return IMFMediaSink_Release(&renderer->IMFMediaSink_iface);
+}
+
+static HRESULT WINAPI video_renderer_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset)
+{
+ struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+
+ TRACE("%p, %s, %s.\n", iface, debugstr_time(systime), debugstr_time(offset));
+
+ EnterCriticalSection(&renderer->cs);
+
+ if (renderer->state == STREAM_STATE_STOPPED)
+ renderer->state = STREAM_STATE_RUNNING;
+
+ IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStarted, &GUID_NULL, S_OK, NULL);
+
+ LeaveCriticalSection(&renderer->cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI video_renderer_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime)
+{
+ struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+
+ TRACE("%p, %s.\n", iface, debugstr_time(systime));
+
+ EnterCriticalSection(&renderer->cs);
+
+ renderer->state = STREAM_STATE_STOPPED;
+ IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStopped, &GUID_NULL, S_OK, NULL);
+
+ LeaveCriticalSection(&renderer->cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI video_renderer_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime)
+{
+ struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %s.\n", iface, debugstr_time(systime));
+
+ EnterCriticalSection(&renderer->cs);
+
+ if (renderer->state == STREAM_STATE_RUNNING)
+ {
+ renderer->state = STREAM_STATE_PAUSED;
+ IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkPaused, &GUID_NULL, S_OK, NULL);
+ }
+ else
+ hr = MF_E_INVALID_STATE_TRANSITION;
+
+ LeaveCriticalSection(&renderer->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI video_renderer_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime)
+{
+ struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+
+ TRACE("%p, %s.\n", iface, debugstr_time(systime));
+
+ EnterCriticalSection(&renderer->cs);
+
+ IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStarted, &GUID_NULL, S_OK, NULL);
+
+ LeaveCriticalSection(&renderer->cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI video_renderer_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME systime, float rate)
+{
+ FIXME("%p, %s, %f.\n", iface, debugstr_time(systime), rate);
+
+ return E_NOTIMPL;
+}
+
+static const IMFClockStateSinkVtbl video_renderer_clock_sink_vtbl =
+{
+ video_renderer_clock_sink_QueryInterface,
+ video_renderer_clock_sink_AddRef,
+ video_renderer_clock_sink_Release,
+ video_renderer_clock_sink_OnClockStart,
+ video_renderer_clock_sink_OnClockStop,
+ video_renderer_clock_sink_OnClockPause,
+ video_renderer_clock_sink_OnClockRestart,
+ video_renderer_clock_sink_OnClockSetRate,
+};
+
HRESULT media_engine_create_video_renderer(IMFTopologyNode **node)
{
struct video_renderer *renderer;
@@ -638,6 +836,7 @@ HRESULT media_engine_create_video_renderer(IMFTopologyNode **node)
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->IMFClockStateSink_iface.lpVtbl = &video_renderer_clock_sink_vtbl;
renderer->refcount = 1;
InitializeCriticalSection(&renderer->cs);
--
2.28.0
Nov. 2, 2020