From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/media_sink.c | 280 +++++++++++++++++++++++++++++++- 1 file changed, 277 insertions(+), 3 deletions(-)
diff --git a/dlls/winegstreamer/media_sink.c b/dlls/winegstreamer/media_sink.c index 1a09c839642..99246fce2ac 100644 --- a/dlls/winegstreamer/media_sink.c +++ b/dlls/winegstreamer/media_sink.c @@ -19,11 +19,26 @@
#include "gst_private.h" #include "mferror.h" +#include "mfapi.h"
#include "wine/debug.h" +#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+struct stream_sink +{ + IMFStreamSink IMFStreamSink_iface; + LONG refcount; + DWORD id; + + IMFMediaType *type; + IMFMediaEventQueue *event_queue; + IMFFinalizableMediaSink *media_sink; + + struct list entry; +}; + struct media_sink { IMFFinalizableMediaSink IMFFinalizableMediaSink_iface; @@ -32,13 +47,224 @@ struct media_sink bool shutdown;
IMFByteStream *bytestream; + + struct list stream_sinks; };
+static struct stream_sink *impl_from_IMFStreamSink(IMFStreamSink *iface) +{ + return CONTAINING_RECORD(iface, struct stream_sink, IMFStreamSink_iface); +} + static struct media_sink *impl_from_IMFFinalizableMediaSink(IMFFinalizableMediaSink *iface) { return CONTAINING_RECORD(iface, struct media_sink, IMFFinalizableMediaSink_iface); }
+static HRESULT WINAPI stream_sink_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj) +{ + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + + TRACE("iface %p, riid %s, obj %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFStreamSink) || + IsEqualGUID(riid, &IID_IMFMediaEventGenerator) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = &stream_sink->IMFStreamSink_iface; + } + else + { + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*obj); + + return S_OK; +} + +static ULONG WINAPI stream_sink_AddRef(IMFStreamSink *iface) +{ + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + ULONG refcount = InterlockedIncrement(&stream_sink->refcount); + TRACE("iface %p, refcount %lu.\n", iface, refcount); + return refcount; +} + +static ULONG WINAPI stream_sink_Release(IMFStreamSink *iface) +{ + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + ULONG refcount = InterlockedDecrement(&stream_sink->refcount); + + TRACE("iface %p, refcount %lu.\n", iface, refcount); + + if (!refcount) + { + IMFMediaEventQueue_Release(stream_sink->event_queue); + IMFFinalizableMediaSink_Release(stream_sink->media_sink); + if (stream_sink->type) + IMFMediaType_Release(stream_sink->type); + free(stream_sink); + } + + return refcount; +} + +static HRESULT WINAPI stream_sink_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event) +{ + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + + TRACE("iface %p, flags %#lx, event %p.\n", iface, flags, event); + + return IMFMediaEventQueue_GetEvent(stream_sink->event_queue, flags, event); +} + +static HRESULT WINAPI stream_sink_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback, + IUnknown *state) +{ + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + + TRACE("iface %p, callback %p, state %p.\n", iface, callback, state); + + return IMFMediaEventQueue_BeginGetEvent(stream_sink->event_queue, callback, state); +} + +static HRESULT WINAPI stream_sink_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result, + IMFMediaEvent **event) +{ + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + + TRACE("iface %p, result %p, event %p.\n", iface, result, event); + + return IMFMediaEventQueue_EndGetEvent(stream_sink->event_queue, result, event); +} + +static HRESULT WINAPI stream_sink_QueueEvent(IMFStreamSink *iface, MediaEventType event_type, + REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) +{ + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + + TRACE("iface %p, event_type %lu, ext_type %s, hr %#lx, value %p.\n", + iface, event_type, debugstr_guid(ext_type), hr, value); + + return IMFMediaEventQueue_QueueEventParamVar(stream_sink->event_queue, event_type, ext_type, hr, value); +} + +static HRESULT WINAPI stream_sink_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **ret) +{ + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + + TRACE("iface %p, ret %p.\n", iface, ret); + + IMFMediaSink_AddRef((*ret = (IMFMediaSink *)&stream_sink->media_sink)); + + return S_OK; +} + +static HRESULT WINAPI stream_sink_GetIdentifier(IMFStreamSink *iface, DWORD *identifier) +{ + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + + TRACE("iface %p, identifier %p.\n", iface, identifier); + + *identifier = stream_sink->id; + + return S_OK; +} + +static HRESULT WINAPI stream_sink_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler) +{ + FIXME("iface %p, handler %p stub!\n", iface, handler); + + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_sink_ProcessSample(IMFStreamSink *iface, IMFSample *sample) +{ + FIXME("iface %p, sample %p stub!\n", iface, sample); + + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_sink_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type, + const PROPVARIANT *marker_value, const PROPVARIANT *context_value) +{ + FIXME("iface %p, marker_type %d, marker_value %p, context_value %p stub!\n", + iface, marker_type, marker_value, context_value); + + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_sink_Flush(IMFStreamSink *iface) +{ + FIXME("iface %p stub!\n", iface); + + return E_NOTIMPL; +} + +static const IMFStreamSinkVtbl stream_sink_vtbl = +{ + stream_sink_QueryInterface, + stream_sink_AddRef, + stream_sink_Release, + stream_sink_GetEvent, + stream_sink_BeginGetEvent, + stream_sink_EndGetEvent, + stream_sink_QueueEvent, + stream_sink_GetMediaSink, + stream_sink_GetIdentifier, + stream_sink_GetMediaTypeHandler, + stream_sink_ProcessSample, + stream_sink_PlaceMarker, + stream_sink_Flush, +}; + +static HRESULT stream_sink_create(DWORD stream_sink_id, IMFMediaType *media_type, struct media_sink *media_sink, + struct stream_sink **out) +{ + struct stream_sink *stream_sink; + HRESULT hr; + + TRACE("stream_sink_id %#lx, media_type %p, media_sink %p, out %p.\n", + stream_sink_id, media_type, media_sink, out); + + if (!(stream_sink = calloc(1, sizeof(*stream_sink)))) + return E_OUTOFMEMORY; + + if (FAILED(hr = MFCreateEventQueue(&stream_sink->event_queue))) + { + free(stream_sink); + return hr; + } + + stream_sink->IMFStreamSink_iface.lpVtbl = &stream_sink_vtbl; + stream_sink->refcount = 1; + stream_sink->id = stream_sink_id; + if (media_type) + IMFMediaType_AddRef((stream_sink->type = media_type)); + IMFFinalizableMediaSink_AddRef((stream_sink->media_sink = &media_sink->IMFFinalizableMediaSink_iface)); + + TRACE("Created stream sink %p.\n", stream_sink); + *out = stream_sink; + + return S_OK; +} + +static struct stream_sink *media_sink_get_stream_sink_by_id(struct media_sink *media_sink, DWORD id) +{ + struct stream_sink *stream_sink; + + LIST_FOR_EACH_ENTRY(stream_sink, &media_sink->stream_sinks, struct stream_sink, entry) + { + if (stream_sink->id == id) + return stream_sink; + } + + return NULL; +} + static HRESULT WINAPI media_sink_QueryInterface(IMFFinalizableMediaSink *iface, REFIID riid, void **obj) { TRACE("iface %p, riid %s, obj %p.\n", iface, debugstr_guid(riid), obj); @@ -97,10 +323,30 @@ static HRESULT WINAPI media_sink_GetCharacteristics(IMFFinalizableMediaSink *ifa static HRESULT WINAPI media_sink_AddStreamSink(IMFFinalizableMediaSink *iface, DWORD stream_sink_id, IMFMediaType *media_type, IMFStreamSink **stream_sink) { - FIXME("iface %p, stream_sink_id %#lx, media_type %p, stream_sink %p stub!\n", + struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface); + struct stream_sink *object; + HRESULT hr; + + TRACE("iface %p, stream_sink_id %#lx, media_type %p, stream_sink %p.\n", iface, stream_sink_id, media_type, stream_sink);
- return E_NOTIMPL; + if (media_sink_get_stream_sink_by_id(media_sink, stream_sink_id)) + return MF_E_STREAMSINK_EXISTS; + + if (FAILED(hr = stream_sink_create(stream_sink_id, media_type, media_sink, &object))) + { + WARN("Failed to create stream sink, hr %#lx.\n", hr); + return hr; + } + + EnterCriticalSection(&media_sink->cs); + list_add_tail(&media_sink->stream_sinks, &object->entry); + LeaveCriticalSection(&media_sink->cs); + + if (stream_sink) + IMFStreamSink_AddRef(*stream_sink = &object->IMFStreamSink_iface); + + return S_OK; }
static HRESULT WINAPI media_sink_RemoveStreamSink(IMFFinalizableMediaSink *iface, DWORD stream_sink_id) @@ -150,6 +396,7 @@ static HRESULT WINAPI media_sink_GetPresentationClock(IMFFinalizableMediaSink *i static HRESULT WINAPI media_sink_Shutdown(IMFFinalizableMediaSink *iface) { struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface); + struct stream_sink *stream_sink;
TRACE("iface %p.\n", iface);
@@ -161,6 +408,12 @@ static HRESULT WINAPI media_sink_Shutdown(IMFFinalizableMediaSink *iface) return MF_E_SHUTDOWN; }
+ LIST_FOR_EACH_ENTRY(stream_sink, &media_sink->stream_sinks, struct stream_sink, entry) + { + IMFMediaEventQueue_Shutdown(stream_sink->event_queue); + IMFStreamSink_Release(&stream_sink->IMFStreamSink_iface); + } + IMFByteStream_Close(media_sink->bytestream);
media_sink->shutdown = TRUE; @@ -253,6 +506,7 @@ static ULONG WINAPI sink_class_factory_Release(IMFSinkClassFactory *iface) static HRESULT WINAPI sink_class_factory_CreateMediaSink(IMFSinkClassFactory *iface, IMFByteStream *bytestream, IMFMediaType *video_type, IMFMediaType *audio_type, IMFMediaSink **out) { + IMFFinalizableMediaSink *media_sink_iface; struct media_sink *media_sink; HRESULT hr;
@@ -261,8 +515,28 @@ static HRESULT WINAPI sink_class_factory_CreateMediaSink(IMFSinkClassFactory *if
if (FAILED(hr = media_sink_create(bytestream, &media_sink))) return hr; + media_sink_iface = &media_sink->IMFFinalizableMediaSink_iface; + + if (video_type) + { + if (FAILED(hr = IMFFinalizableMediaSink_AddStreamSink(media_sink_iface, 1, video_type, NULL))) + { + IMFFinalizableMediaSink_Shutdown(media_sink_iface); + IMFFinalizableMediaSink_Release(media_sink_iface); + return hr; + } + } + if (audio_type) + { + if (FAILED(hr = IMFFinalizableMediaSink_AddStreamSink(media_sink_iface, 2, audio_type, NULL))) + { + IMFFinalizableMediaSink_Shutdown(media_sink_iface); + IMFFinalizableMediaSink_Release(media_sink_iface); + return hr; + } + }
- *out = (IMFMediaSink *)&media_sink->IMFFinalizableMediaSink_iface; + *out = (IMFMediaSink *)media_sink_iface; return S_OK; }