[PATCH 3/5] mf/evr: Implement stream sinks management functionality.
Nikolay Sivov
nsivov at codeweavers.com
Mon Sep 7 04:43:35 CDT 2020
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/mf/evr.c | 347 ++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 334 insertions(+), 13 deletions(-)
diff --git a/dlls/mf/evr.c b/dlls/mf/evr.c
index fe73f6a4a0c..86242611a47 100644
--- a/dlls/mf/evr.c
+++ b/dlls/mf/evr.c
@@ -32,6 +32,16 @@ enum video_renderer_flags
EVR_PRESENTER_INITED_SERVICES = 0x8,
};
+struct video_renderer;
+
+struct video_stream
+{
+ IMFStreamSink IMFStreamSink_iface;
+ LONG refcount;
+ unsigned int id;
+ struct video_renderer *parent;
+};
+
struct video_renderer
{
IMFMediaSink IMFMediaSink_iface;
@@ -50,6 +60,11 @@ struct video_renderer
IMFTransform *mixer;
IMFVideoPresenter *presenter;
unsigned int flags;
+
+ struct video_stream **streams;
+ size_t stream_size;
+ size_t stream_count;
+
CRITICAL_SECTION cs;
};
@@ -93,6 +108,11 @@ static struct video_renderer *impl_from_IMediaEventSink(IMediaEventSink *iface)
return CONTAINING_RECORD(iface, struct video_renderer, IMediaEventSink_iface);
}
+static struct video_stream *impl_from_IMFStreamSink(IMFStreamSink *iface)
+{
+ return CONTAINING_RECORD(iface, struct video_stream, IMFStreamSink_iface);
+}
+
static void video_renderer_release_services(struct video_renderer *renderer)
{
IMFTopologyServiceLookupClient *lookup_client;
@@ -114,6 +134,176 @@ static void video_renderer_release_services(struct video_renderer *renderer)
}
}
+static HRESULT WINAPI video_stream_sink_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj)
+{
+ if (IsEqualIID(riid, &IID_IMFStreamSink) ||
+ IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = iface;
+ IMFStreamSink_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("Unsupported interface %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI video_stream_sink_AddRef(IMFStreamSink *iface)
+{
+ struct video_stream *stream = impl_from_IMFStreamSink(iface);
+ ULONG refcount = InterlockedIncrement(&stream->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI video_stream_sink_Release(IMFStreamSink *iface)
+{
+ struct video_stream *stream = impl_from_IMFStreamSink(iface);
+ ULONG refcount = InterlockedDecrement(&stream->refcount);
+
+ if (!refcount)
+ {
+ heap_free(stream);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI video_stream_sink_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event)
+{
+ FIXME("%p, %#x, %p.\n", iface, flags, event);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_stream_sink_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback, IUnknown *state)
+{
+ FIXME("%p, %p, %p.\n", iface, callback, state);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_stream_sink_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result,
+ IMFMediaEvent **event)
+{
+ FIXME("%p, %p, %p.\n", iface, result, event);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_stream_sink_QueueEvent(IMFStreamSink *iface, MediaEventType event_type,
+ REFGUID exttype, HRESULT hr_status, const PROPVARIANT *value)
+{
+ FIXME("%p, %d, %s, %#x, %p.\n", iface, event_type, debugstr_guid(exttype), hr_status, value);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_stream_sink_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **sink)
+{
+ struct video_stream *stream = impl_from_IMFStreamSink(iface);
+
+ TRACE("%p, %p.\n", iface, sink);
+
+ if (!stream->parent)
+ return MF_E_STREAMSINK_REMOVED;
+
+ if (!sink)
+ return E_POINTER;
+
+ /* FIXME: not entirely safe if sink is being shut down. */
+ *sink = &stream->parent->IMFMediaSink_iface;
+ IMFMediaSink_AddRef(*sink);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI video_stream_sink_GetIdentifier(IMFStreamSink *iface, DWORD *id)
+{
+ struct video_stream *stream = impl_from_IMFStreamSink(iface);
+
+ TRACE("%p, %p.\n", iface, id);
+
+ if (!stream->parent)
+ return MF_E_STREAMSINK_REMOVED;
+
+ if (!id)
+ return E_INVALIDARG;
+
+ *id = stream->id;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI video_stream_sink_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler)
+{
+ FIXME("%p, %p.\n", iface, handler);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_stream_sink_ProcessSample(IMFStreamSink *iface, IMFSample *sample)
+{
+ FIXME("%p, %p.\n", iface, sample);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_stream_sink_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type,
+ const PROPVARIANT *marker_value, const PROPVARIANT *context_value)
+{
+ FIXME("%p, %d, %p, %p.\n", iface, marker_type, marker_value, context_value);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI video_stream_sink_Flush(IMFStreamSink *iface)
+{
+ FIXME("%p.\n", iface);
+
+ return E_NOTIMPL;
+}
+
+static const IMFStreamSinkVtbl video_stream_sink_vtbl =
+{
+ video_stream_sink_QueryInterface,
+ video_stream_sink_AddRef,
+ video_stream_sink_Release,
+ video_stream_sink_GetEvent,
+ video_stream_sink_BeginGetEvent,
+ video_stream_sink_EndGetEvent,
+ video_stream_sink_QueueEvent,
+ video_stream_sink_GetMediaSink,
+ video_stream_sink_GetIdentifier,
+ video_stream_sink_GetMediaTypeHandler,
+ video_stream_sink_ProcessSample,
+ video_stream_sink_PlaceMarker,
+ video_stream_sink_Flush,
+};
+
+static HRESULT video_renderer_stream_create(struct video_renderer *renderer, unsigned int id,
+ struct video_stream **ret)
+{
+ struct video_stream *stream;
+
+ if (!(stream = heap_alloc_zero(sizeof(*stream))))
+ return E_OUTOFMEMORY;
+
+ stream->IMFStreamSink_iface.lpVtbl = &video_stream_sink_vtbl;
+ stream->refcount = 1;
+ stream->parent = renderer;
+ IMFMediaSink_AddRef(&stream->parent->IMFMediaSink_iface);
+ stream->id = id;
+
+ *ret = stream;
+
+ return S_OK;
+}
+
static HRESULT WINAPI video_renderer_sink_QueryInterface(IMFMediaSink *iface, REFIID riid, void **obj)
{
struct video_renderer *renderer = impl_from_IMFMediaSink(iface);
@@ -203,42 +393,161 @@ static HRESULT WINAPI video_renderer_sink_GetCharacteristics(IMFMediaSink *iface
return S_OK;
}
-static HRESULT WINAPI video_renderer_sink_AddStreamSink(IMFMediaSink *iface, DWORD stream_sink_id,
+static HRESULT WINAPI video_renderer_sink_AddStreamSink(IMFMediaSink *iface, DWORD id,
IMFMediaType *media_type, IMFStreamSink **stream_sink)
{
- FIXME("%p, %#x, %p, %p.\n", iface, stream_sink_id, media_type, stream_sink);
+ struct video_renderer *renderer = impl_from_IMFMediaSink(iface);
+ struct video_stream *stream;
+ HRESULT hr;
- return E_NOTIMPL;
+ TRACE("%p, %#x, %p, %p.\n", iface, id, media_type, stream_sink);
+
+ /* Rely on mixer for stream id validation. */
+
+ EnterCriticalSection(&renderer->cs);
+ if (renderer->flags & EVR_SHUT_DOWN)
+ hr = MF_E_SHUTDOWN;
+ else if (SUCCEEDED(hr = IMFTransform_AddInputStreams(renderer->mixer, 1, &id)))
+ {
+ if (mf_array_reserve((void **)&renderer->streams, &renderer->stream_size, renderer->stream_count + 1,
+ sizeof(*renderer->streams)))
+ {
+ if (SUCCEEDED(hr = video_renderer_stream_create(renderer, id, &stream)))
+ {
+ *stream_sink = &stream->IMFStreamSink_iface;
+ IMFStreamSink_AddRef(*stream_sink);
+ renderer->streams[renderer->stream_count++] = stream;
+ }
+ }
+ else
+ hr = E_OUTOFMEMORY;
+
+ if (FAILED(hr))
+ IMFTransform_DeleteInputStream(renderer->mixer, id);
+
+ }
+ LeaveCriticalSection(&renderer->cs);
+
+ return hr;
}
-static HRESULT WINAPI video_renderer_sink_RemoveStreamSink(IMFMediaSink *iface, DWORD stream_sink_id)
+static HRESULT WINAPI video_renderer_sink_RemoveStreamSink(IMFMediaSink *iface, DWORD id)
{
- FIXME("%p, %#x.\n", iface, stream_sink_id);
+ struct video_renderer *renderer = impl_from_IMFMediaSink(iface);
+ HRESULT hr;
+ size_t i;
- return E_NOTIMPL;
+ TRACE("%p, %#x.\n", iface, id);
+
+ /* Rely on mixer for stream id validation. */
+
+ EnterCriticalSection(&renderer->cs);
+ if (renderer->flags & EVR_SHUT_DOWN)
+ hr = MF_E_SHUTDOWN;
+ else if (SUCCEEDED(hr = IMFTransform_DeleteInputStream(renderer->mixer, id)))
+ {
+ for (i = 0; i < renderer->stream_count; ++i)
+ {
+ if (renderer->streams[i]->id == id)
+ {
+ IMFStreamSink_Release(&renderer->streams[i]->IMFStreamSink_iface);
+ renderer->streams[i] = NULL;
+ if (i < renderer->stream_count - 1)
+ {
+ memmove(&renderer->streams[i], &renderer->streams[i+1],
+ (renderer->stream_count - i - 1) * sizeof(*renderer->streams));
+ }
+ renderer->stream_count--;
+ break;
+ }
+ }
+ }
+ LeaveCriticalSection(&renderer->cs);
+
+ return hr;
}
static HRESULT WINAPI video_renderer_sink_GetStreamSinkCount(IMFMediaSink *iface, DWORD *count)
{
- FIXME("%p, %p.\n", iface, count);
+ struct video_renderer *renderer = impl_from_IMFMediaSink(iface);
+ HRESULT hr = S_OK;
- return E_NOTIMPL;
+ TRACE("%p, %p.\n", iface, count);
+
+ if (!count)
+ return E_POINTER;
+
+ EnterCriticalSection(&renderer->cs);
+ if (renderer->flags & EVR_SHUT_DOWN)
+ hr = MF_E_SHUTDOWN;
+ else if (!count)
+ hr = E_POINTER;
+ else
+ *count = renderer->stream_count;
+ LeaveCriticalSection(&renderer->cs);
+
+ return hr;
}
static HRESULT WINAPI video_renderer_sink_GetStreamSinkByIndex(IMFMediaSink *iface, DWORD index,
IMFStreamSink **stream)
{
- FIXME("%p, %u, %p.\n", iface, index, stream);
+ struct video_renderer *renderer = impl_from_IMFMediaSink(iface);
+ HRESULT hr = S_OK;
- return E_NOTIMPL;
+ TRACE("%p, %u, %p.\n", iface, index, stream);
+
+ EnterCriticalSection(&renderer->cs);
+ if (renderer->flags & EVR_SHUT_DOWN)
+ hr = MF_E_SHUTDOWN;
+ else if (!stream)
+ hr = E_POINTER;
+ else if (index >= renderer->stream_count)
+ hr = E_INVALIDARG;
+ else
+ {
+ *stream = &renderer->streams[index]->IMFStreamSink_iface;
+ IMFStreamSink_AddRef(*stream);
+ }
+ LeaveCriticalSection(&renderer->cs);
+
+ return hr;
}
-static HRESULT WINAPI video_renderer_sink_GetStreamSinkById(IMFMediaSink *iface, DWORD stream_sink_id,
+static HRESULT WINAPI video_renderer_sink_GetStreamSinkById(IMFMediaSink *iface, DWORD id,
IMFStreamSink **stream)
{
- FIXME("%p, %#x, %p.\n", iface, stream_sink_id, stream);
+ struct video_renderer *renderer = impl_from_IMFMediaSink(iface);
+ HRESULT hr = S_OK;
+ size_t i;
- return E_NOTIMPL;
+ TRACE("%p, %#x, %p.\n", iface, id, stream);
+
+ EnterCriticalSection(&renderer->cs);
+ if (renderer->flags & EVR_SHUT_DOWN)
+ hr = MF_E_SHUTDOWN;
+ else if (!stream)
+ hr = E_POINTER;
+ else
+ {
+ for (i = 0; i < renderer->stream_count; ++i)
+ {
+ if (renderer->streams[i]->id == id)
+ break;
+ }
+
+ if (i == renderer->stream_count)
+ hr = MF_E_INVALIDSTREAMNUMBER;
+ else
+ {
+ *stream = &renderer->streams[i]->IMFStreamSink_iface;
+ IMFStreamSink_AddRef(*stream);
+ }
+
+ }
+ LeaveCriticalSection(&renderer->cs);
+
+ return hr;
}
static void video_renderer_set_presentation_clock(struct video_renderer *renderer, IMFPresentationClock *clock)
@@ -305,6 +614,7 @@ static HRESULT WINAPI video_renderer_sink_GetPresentationClock(IMFMediaSink *ifa
static HRESULT WINAPI video_renderer_sink_Shutdown(IMFMediaSink *iface)
{
struct video_renderer *renderer = impl_from_IMFMediaSink(iface);
+ size_t i;
TRACE("%p.\n", iface);
@@ -313,6 +623,17 @@ static HRESULT WINAPI video_renderer_sink_Shutdown(IMFMediaSink *iface)
EnterCriticalSection(&renderer->cs);
renderer->flags |= EVR_SHUT_DOWN;
+ /* Detach streams from the sink. */
+ for (i = 0; i < renderer->stream_count; ++i)
+ {
+ IMFMediaSink_Release(&renderer->streams[i]->parent->IMFMediaSink_iface);
+ renderer->streams[i]->parent = NULL;
+ IMFStreamSink_Release(&renderer->streams[i]->IMFStreamSink_iface);
+ renderer->streams[i] = NULL;
+ }
+ heap_free(renderer->streams);
+ renderer->stream_count = 0;
+ renderer->stream_size = 0;
IMFMediaEventQueue_Shutdown(renderer->event_queue);
video_renderer_set_presentation_clock(renderer, NULL);
video_renderer_release_services(renderer);
--
2.28.0
More information about the wine-devel
mailing list