There is a working in progress winegstreamer muxer backend: !3303 This patch set is the windows api side(frontend) of the muxer stuff.
It will make the patch set too large to submit the backend and frontend together, so I decide to submit the frontend first.
-- v3: winegstreamer: Add async command handling to media sink. winegstreamer: Add IMFClockStateSink stubs to media sink. winegstreamer: Implement IMFMediaEventGenerator for media sink. winegstreamer: Add IMFMediaTypeHandler stubs to stream sink. winegstreamer: Implement IMFMediaEventGenerator for stream sink. winegstreamer: Add stubs for stream sink. winegstreamer: Add stubs for media sink.
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 2 + dlls/winegstreamer/main.c | 3 + dlls/winegstreamer/media_sink.c | 284 +++++++++++++++++++ dlls/winegstreamer/winegstreamer_classes.idl | 6 + 5 files changed, 296 insertions(+) create mode 100644 dlls/winegstreamer/media_sink.c
diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 1c701bfa9f6..78bdd6c0ef1 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -11,6 +11,7 @@ C_SRCS = \ color_convert.c \ h264_decoder.c \ main.c \ + media_sink.c \ media_source.c \ mfplat.c \ quartz_parser.c \ diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 920ffc9d252..ed867f741d9 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -35,6 +35,7 @@ #include "mfidl.h" #include "wine/debug.h" #include "wine/strmbase.h" +#include "wine/mfinternal.h"
#include "unixlib.h"
@@ -121,6 +122,7 @@ HRESULT wma_decoder_create(IUnknown *outer, IUnknown **out); HRESULT wmv_decoder_create(IUnknown *outer, IUnknown **out); HRESULT resampler_create(IUnknown *outer, IUnknown **out); HRESULT color_convert_create(IUnknown *outer, IUnknown **out); +HRESULT sink_class_factory_create(IUnknown *outer, IUnknown **out);
bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool wm); bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index a92d440c42f..9624c469314 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -612,6 +612,7 @@ static struct class_factory wma_decoder_cf = {{&class_factory_vtbl}, wma_decoder static struct class_factory wmv_decoder_cf = {{&class_factory_vtbl}, wmv_decoder_create}; static struct class_factory resampler_cf = {{&class_factory_vtbl}, resampler_create}; static struct class_factory color_convert_cf = {{&class_factory_vtbl}, color_convert_create}; +static struct class_factory sink_class_factory_cf = {{&class_factory_vtbl}, sink_class_factory_create};
HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **out) { @@ -646,6 +647,8 @@ HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **out) factory = &resampler_cf; else if (IsEqualGUID(clsid, &CLSID_CColorConvertDMO)) factory = &color_convert_cf; + else if (IsEqualGUID(clsid, &CLSID_MFMP3SinkClassFactory)) + factory = &sink_class_factory_cf; else { FIXME("%s not implemented, returning CLASS_E_CLASSNOTAVAILABLE.\n", debugstr_guid(clsid)); diff --git a/dlls/winegstreamer/media_sink.c b/dlls/winegstreamer/media_sink.c new file mode 100644 index 00000000000..4f60a0955d0 --- /dev/null +++ b/dlls/winegstreamer/media_sink.c @@ -0,0 +1,284 @@ +/* Gstreamer Media Sink + * + * Copyright 2023 Ziqing Hui 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 + */ + +#include "gst_private.h" +#include "mferror.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +struct media_sink +{ + IMFFinalizableMediaSink IMFFinalizableMediaSink_iface; + LONG refcount; + CRITICAL_SECTION cs; + bool shutdown; + + IMFByteStream *bytestream; +}; + +static struct media_sink *impl_from_IMFFinalizableMediaSink(IMFFinalizableMediaSink *iface) +{ + return CONTAINING_RECORD(iface, struct media_sink, IMFFinalizableMediaSink_iface); +} + +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); + + if (IsEqualIID(riid, &IID_IMFFinalizableMediaSink) || + IsEqualIID(riid, &IID_IMFMediaSink) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = 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 media_sink_AddRef(IMFFinalizableMediaSink *iface) +{ + struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface); + ULONG refcount = InterlockedIncrement(&media_sink->refcount); + TRACE("iface %p, refcount %lu.\n", iface, refcount); + return refcount; +} + +static ULONG WINAPI media_sink_Release(IMFFinalizableMediaSink *iface) +{ + struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface); + ULONG refcount = InterlockedDecrement(&media_sink->refcount); + + TRACE("iface %p, refcount %lu.\n", iface, refcount); + + if (!refcount) + { + IMFFinalizableMediaSink_Shutdown(iface); + IMFByteStream_Release(media_sink->bytestream); + media_sink->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&media_sink->cs); + free(media_sink); + } + + return refcount; +} + +static HRESULT WINAPI media_sink_GetCharacteristics(IMFFinalizableMediaSink *iface, DWORD *flags) +{ + FIXME("iface %p, flags %p stub!\n", iface, flags); + + return E_NOTIMPL; +} + +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", + iface, stream_sink_id, media_type, stream_sink); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_sink_RemoveStreamSink(IMFFinalizableMediaSink *iface, DWORD stream_sink_id) +{ + FIXME("iface %p, stream_sink_id %#lx stub!\n", iface, stream_sink_id); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_sink_GetStreamSinkCount(IMFFinalizableMediaSink *iface, DWORD *count) +{ + FIXME("iface %p, count %p stub!\n", iface, count); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_sink_GetStreamSinkByIndex(IMFFinalizableMediaSink *iface, DWORD index, + IMFStreamSink **stream) +{ + FIXME("iface %p, index %lu, stream %p stub!\n", iface, index, stream); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_sink_GetStreamSinkById(IMFFinalizableMediaSink *iface, DWORD stream_sink_id, + IMFStreamSink **stream) +{ + FIXME("iface %p, stream_sink_id %#lx, stream %p stub!\n", iface, stream_sink_id, stream); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_sink_SetPresentationClock(IMFFinalizableMediaSink *iface, IMFPresentationClock *clock) +{ + FIXME("iface %p, clock %p stub!\n", iface, clock); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_sink_GetPresentationClock(IMFFinalizableMediaSink *iface, IMFPresentationClock **clock) +{ + FIXME("iface %p, clock %p stub!\n", iface, clock); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_sink_Shutdown(IMFFinalizableMediaSink *iface) +{ + struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface); + + TRACE("iface %p.\n", iface); + + EnterCriticalSection(&media_sink->cs); + + if (media_sink->shutdown) + { + LeaveCriticalSection(&media_sink->cs); + return MF_E_SHUTDOWN; + } + + IMFByteStream_Close(media_sink->bytestream); + + media_sink->shutdown = TRUE; + + LeaveCriticalSection(&media_sink->cs); + + return S_OK; +} + +static HRESULT WINAPI media_sink_BeginFinalize(IMFFinalizableMediaSink *iface, IMFAsyncCallback *callback, IUnknown *state) +{ + FIXME("iface %p, callback %p, state %p stub!\n", iface, callback, state); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_sink_EndFinalize(IMFFinalizableMediaSink *iface, IMFAsyncResult *result) +{ + FIXME("iface %p, result %p stub!\n", iface, result); + + return E_NOTIMPL; +} + +static const IMFFinalizableMediaSinkVtbl media_sink_vtbl = +{ + media_sink_QueryInterface, + media_sink_AddRef, + media_sink_Release, + media_sink_GetCharacteristics, + media_sink_AddStreamSink, + media_sink_RemoveStreamSink, + media_sink_GetStreamSinkCount, + media_sink_GetStreamSinkByIndex, + media_sink_GetStreamSinkById, + media_sink_SetPresentationClock, + media_sink_GetPresentationClock, + media_sink_Shutdown, + media_sink_BeginFinalize, + media_sink_EndFinalize, +}; + +static HRESULT media_sink_create(IMFByteStream *bytestream, struct media_sink **out) +{ + struct media_sink *media_sink; + + TRACE("bytestream %p, out %p.\n", bytestream, out); + + if (!bytestream) + return E_POINTER; + + if (!(media_sink = calloc(1, sizeof(*media_sink)))) + return E_OUTOFMEMORY; + + media_sink->IMFFinalizableMediaSink_iface.lpVtbl = &media_sink_vtbl; + media_sink->refcount = 1; + InitializeCriticalSection(&media_sink->cs); + media_sink->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs"); + IMFByteStream_AddRef((media_sink->bytestream = bytestream)); + + *out = media_sink; + TRACE("Created media sink %p.\n", media_sink); + + return S_OK; +} + +static HRESULT WINAPI sink_class_factory_QueryInterface(IMFSinkClassFactory *iface, REFIID riid, void **out) +{ + if (IsEqualIID(riid, &IID_IMFSinkClassFactory) + || IsEqualIID(riid, &IID_IUnknown)) + { + *out = iface; + IMFSinkClassFactory_AddRef(iface); + return S_OK; + } + + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI sink_class_factory_AddRef(IMFSinkClassFactory *iface) +{ + return 2; +} + +static ULONG WINAPI sink_class_factory_Release(IMFSinkClassFactory *iface) +{ + return 1; +} + +static HRESULT WINAPI sink_class_factory_CreateMediaSink(IMFSinkClassFactory *iface, IMFByteStream *bytestream, + IMFMediaType *video_type, IMFMediaType *audio_type, IMFMediaSink **out) +{ + struct media_sink *media_sink; + HRESULT hr; + + TRACE("iface %p, bytestream %p, video_type %p, audio_type %p, out %p.\n", + iface, bytestream, video_type, audio_type, out); + + if (FAILED(hr = media_sink_create(bytestream, &media_sink))) + return hr; + + *out = (IMFMediaSink *)&media_sink->IMFFinalizableMediaSink_iface; + return S_OK; +} + +static const IMFSinkClassFactoryVtbl sink_class_factory_vtbl = +{ + sink_class_factory_QueryInterface, + sink_class_factory_AddRef, + sink_class_factory_Release, + sink_class_factory_CreateMediaSink, +}; + +static IMFSinkClassFactory sink_class_factory = { &sink_class_factory_vtbl }; + +HRESULT sink_class_factory_create(IUnknown *outer, IUnknown **out) +{ + *out = (IUnknown *)&sink_class_factory; + return S_OK; +} diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl index 30a99c9acfb..2bc85e70b3a 100644 --- a/dlls/winegstreamer/winegstreamer_classes.idl +++ b/dlls/winegstreamer/winegstreamer_classes.idl @@ -111,3 +111,9 @@ coclass CResamplerMediaObject {} uuid(98230571-0087-4204-b020-3282538e57d3) ] coclass CColorConvertDMO {} + +[ + threading(both), + uuid(11275a82-5e5a-47fd-a01c-3683c12fb196) +] +coclass MFMP3SinkClassFactory {}
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/media_sink.c | 266 +++++++++++++++++++++++++++++++- 1 file changed, 263 insertions(+), 3 deletions(-)
diff --git a/dlls/winegstreamer/media_sink.c b/dlls/winegstreamer/media_sink.c index 4f60a0955d0..9abfbef1867 100644 --- a/dlls/winegstreamer/media_sink.c +++ b/dlls/winegstreamer/media_sink.c @@ -19,11 +19,25 @@
#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; + IMFFinalizableMediaSink *media_sink; + + struct list entry; +}; + struct media_sink { IMFFinalizableMediaSink IMFFinalizableMediaSink_iface; @@ -32,13 +46,208 @@ 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) + { + 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) +{ + FIXME("iface %p, flags %#lx, event %p.\n", iface, flags, event); + + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_sink_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback, + IUnknown *state) +{ + FIXME("iface %p, callback %p, state %p.\n", iface, callback, state); + + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_sink_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result, + IMFMediaEvent **event) +{ + FIXME("iface %p, result %p, event %p.\n", iface, result, event); + + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_sink_QueueEvent(IMFStreamSink *iface, MediaEventType event_type, + REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) +{ + FIXME("iface %p, event_type %lu, ext_type %s, hr %#lx, value %p.\n", + iface, event_type, debugstr_guid(ext_type), hr, value); + + return E_NOTIMPL; +} + +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; + + 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; + + 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); @@ -98,10 +307,32 @@ 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; + EnterCriticalSection(&media_sink->cs); + + 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; + } + + 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) @@ -151,6 +382,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, *next;
TRACE("iface %p.\n", iface);
@@ -162,6 +394,12 @@ static HRESULT WINAPI media_sink_Shutdown(IMFFinalizableMediaSink *iface) return MF_E_SHUTDOWN; }
+ LIST_FOR_EACH_ENTRY_SAFE(stream_sink, next, &media_sink->stream_sinks, struct stream_sink, entry) + { + list_remove(&stream_sink->entry); + IMFStreamSink_Release(&stream_sink->IMFStreamSink_iface); + } + IMFByteStream_Close(media_sink->bytestream);
media_sink->shutdown = TRUE; @@ -220,6 +458,7 @@ static HRESULT media_sink_create(IMFByteStream *bytestream, struct media_sink ** InitializeCriticalSection(&media_sink->cs); media_sink->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs"); IMFByteStream_AddRef((media_sink->bytestream = bytestream)); + list_init(&media_sink->stream_sinks);
*out = media_sink; TRACE("Created media sink %p.\n", media_sink); @@ -254,6 +493,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;
@@ -262,8 +502,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; }
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/media_sink.c | 34 +++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-)
diff --git a/dlls/winegstreamer/media_sink.c b/dlls/winegstreamer/media_sink.c index 9abfbef1867..afbb908d76d 100644 --- a/dlls/winegstreamer/media_sink.c +++ b/dlls/winegstreamer/media_sink.c @@ -34,6 +34,7 @@ struct stream_sink
IMFMediaType *type; IMFFinalizableMediaSink *media_sink; + IMFMediaEventQueue *event_queue;
struct list entry; }; @@ -101,6 +102,7 @@ static ULONG WINAPI stream_sink_Release(IMFStreamSink *iface)
if (!refcount) { + IMFMediaEventQueue_Release(stream_sink->event_queue); IMFFinalizableMediaSink_Release(stream_sink->media_sink); if (stream_sink->type) IMFMediaType_Release(stream_sink->type); @@ -112,34 +114,42 @@ static ULONG WINAPI stream_sink_Release(IMFStreamSink *iface)
static HRESULT WINAPI stream_sink_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event) { - FIXME("iface %p, flags %#lx, event %p.\n", iface, flags, event); + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface);
- return E_NOTIMPL; + 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) { - FIXME("iface %p, callback %p, state %p.\n", iface, callback, state); + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface);
- return E_NOTIMPL; + 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) { - FIXME("iface %p, result %p, event %p.\n", iface, result, event); + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface);
- return E_NOTIMPL; + 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) { - FIXME("iface %p, event_type %lu, ext_type %s, hr %#lx, value %p.\n", + 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 E_NOTIMPL; + return IMFMediaEventQueue_QueueEventParamVar(stream_sink->event_queue, event_type, ext_type, hr, value); }
static HRESULT WINAPI stream_sink_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **ret) @@ -215,6 +225,7 @@ static HRESULT stream_sink_create(DWORD stream_sink_id, IMFMediaType *media_type 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); @@ -222,6 +233,12 @@ static HRESULT stream_sink_create(DWORD stream_sink_id, IMFMediaType *media_type 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; @@ -397,6 +414,7 @@ static HRESULT WINAPI media_sink_Shutdown(IMFFinalizableMediaSink *iface) LIST_FOR_EACH_ENTRY_SAFE(stream_sink, next, &media_sink->stream_sinks, struct stream_sink, entry) { list_remove(&stream_sink->entry); + IMFMediaEventQueue_Shutdown(stream_sink->event_queue); IMFStreamSink_Release(&stream_sink->IMFStreamSink_iface); }
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/media_sink.c | 95 +++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+)
diff --git a/dlls/winegstreamer/media_sink.c b/dlls/winegstreamer/media_sink.c index afbb908d76d..abddb486ff1 100644 --- a/dlls/winegstreamer/media_sink.c +++ b/dlls/winegstreamer/media_sink.c @@ -29,6 +29,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); struct stream_sink { IMFStreamSink IMFStreamSink_iface; + IMFMediaTypeHandler IMFMediaTypeHandler_iface; LONG refcount; DWORD id;
@@ -56,6 +57,11 @@ static struct stream_sink *impl_from_IMFStreamSink(IMFStreamSink *iface) return CONTAINING_RECORD(iface, struct stream_sink, IMFStreamSink_iface); }
+static struct stream_sink *impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler *iface) +{ + return CONTAINING_RECORD(iface, struct stream_sink, IMFMediaTypeHandler_iface); +} + static struct media_sink *impl_from_IMFFinalizableMediaSink(IMFFinalizableMediaSink *iface) { return CONTAINING_RECORD(iface, struct media_sink, IMFFinalizableMediaSink_iface); @@ -73,6 +79,10 @@ static HRESULT WINAPI stream_sink_QueryInterface(IMFStreamSink *iface, REFIID ri { *obj = &stream_sink->IMFStreamSink_iface; } + else if (IsEqualIID(riid, &IID_IMFMediaTypeHandler)) + { + *obj = &stream_sink->IMFMediaTypeHandler_iface; + } else { WARN("Unsupported interface %s.\n", debugstr_guid(riid)); @@ -221,6 +231,90 @@ static const IMFStreamSinkVtbl stream_sink_vtbl = stream_sink_Flush, };
+static HRESULT WINAPI stream_sink_type_handler_QueryInterface(IMFMediaTypeHandler *iface, REFIID riid, void **obj) +{ + struct stream_sink *stream_sink = impl_from_IMFMediaTypeHandler(iface); + return IMFStreamSink_QueryInterface(&stream_sink->IMFStreamSink_iface, riid, obj); +} + +static ULONG WINAPI stream_sink_type_handler_AddRef(IMFMediaTypeHandler *iface) +{ + struct stream_sink *stream_sink = impl_from_IMFMediaTypeHandler(iface); + return IMFStreamSink_AddRef(&stream_sink->IMFStreamSink_iface); +} + +static ULONG WINAPI stream_sink_type_handler_Release(IMFMediaTypeHandler *iface) +{ + struct stream_sink *stream_sink = impl_from_IMFMediaTypeHandler(iface); + return IMFStreamSink_Release(&stream_sink->IMFStreamSink_iface); +} + +static HRESULT WINAPI stream_sink_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler *iface, + IMFMediaType *in_type, IMFMediaType **out_type) +{ + FIXME("iface %p, in_type %p, out_type %p.\n", iface, in_type, out_type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_sink_type_handler_GetMediaTypeCount(IMFMediaTypeHandler *iface, DWORD *count) +{ + FIXME("iface %p, count %p.\n", iface, count); + + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_sink_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler *iface, DWORD index, + IMFMediaType **type) +{ + FIXME("iface %p, index %lu, type %p.\n", iface, index, type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_sink_type_handler_SetCurrentMediaType(IMFMediaTypeHandler *iface, IMFMediaType *type) +{ + FIXME("iface %p, type %p.\n", iface, type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_sink_type_handler_GetCurrentMediaType(IMFMediaTypeHandler *iface, IMFMediaType **type) +{ + struct stream_sink *stream_sink = impl_from_IMFMediaTypeHandler(iface); + + TRACE("iface %p, type %p.\n", iface, type); + + if (!type) + return E_POINTER; + if (!stream_sink->type) + return MF_E_NOT_INITIALIZED; + + IMFMediaType_AddRef((*type = stream_sink->type)); + + return S_OK; +} + +static HRESULT WINAPI stream_sink_type_handler_GetMajorType(IMFMediaTypeHandler *iface, GUID *type) +{ + FIXME("iface %p, type %p.\n", iface, type); + + return E_NOTIMPL; +} + +static const IMFMediaTypeHandlerVtbl stream_sink_type_handler_vtbl = +{ + stream_sink_type_handler_QueryInterface, + stream_sink_type_handler_AddRef, + stream_sink_type_handler_Release, + stream_sink_type_handler_IsMediaTypeSupported, + stream_sink_type_handler_GetMediaTypeCount, + stream_sink_type_handler_GetMediaTypeByIndex, + stream_sink_type_handler_SetCurrentMediaType, + stream_sink_type_handler_GetCurrentMediaType, + stream_sink_type_handler_GetMajorType, +}; + static HRESULT stream_sink_create(DWORD stream_sink_id, IMFMediaType *media_type, struct media_sink *media_sink, struct stream_sink **out) { @@ -240,6 +334,7 @@ static HRESULT stream_sink_create(DWORD stream_sink_id, IMFMediaType *media_type }
stream_sink->IMFStreamSink_iface.lpVtbl = &stream_sink_vtbl; + stream_sink->IMFMediaTypeHandler_iface.lpVtbl = &stream_sink_type_handler_vtbl; stream_sink->refcount = 1; stream_sink->id = stream_sink_id; if (media_type)
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/media_sink.c | 100 +++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/media_sink.c b/dlls/winegstreamer/media_sink.c index abddb486ff1..7ef57c3aa22 100644 --- a/dlls/winegstreamer/media_sink.c +++ b/dlls/winegstreamer/media_sink.c @@ -43,11 +43,13 @@ struct stream_sink struct media_sink { IMFFinalizableMediaSink IMFFinalizableMediaSink_iface; + IMFMediaEventGenerator IMFMediaEventGenerator_iface; LONG refcount; CRITICAL_SECTION cs; bool shutdown;
IMFByteStream *bytestream; + IMFMediaEventQueue *event_queue;
struct list stream_sinks; }; @@ -67,6 +69,11 @@ static struct media_sink *impl_from_IMFFinalizableMediaSink(IMFFinalizableMediaS return CONTAINING_RECORD(iface, struct media_sink, IMFFinalizableMediaSink_iface); }
+static struct media_sink *impl_from_IMFMediaEventGenerator(IMFMediaEventGenerator *iface) +{ + return CONTAINING_RECORD(iface, struct media_sink, IMFMediaEventGenerator_iface); +} + static HRESULT WINAPI stream_sink_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj) { struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); @@ -186,9 +193,13 @@ static HRESULT WINAPI stream_sink_GetIdentifier(IMFStreamSink *iface, DWORD *ide
static HRESULT WINAPI stream_sink_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler) { - FIXME("iface %p, handler %p stub!\n", iface, handler); + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface);
- return E_NOTIMPL; + TRACE("iface %p, handler %p.\n", iface, handler); + + IMFMediaTypeHandler_AddRef((*handler = &stream_sink->IMFMediaTypeHandler_iface)); + + return S_OK; }
static HRESULT WINAPI stream_sink_ProcessSample(IMFStreamSink *iface, IMFSample *sample) @@ -362,6 +373,8 @@ static struct stream_sink *media_sink_get_stream_sink_by_id(struct media_sink *m
static HRESULT WINAPI media_sink_QueryInterface(IMFFinalizableMediaSink *iface, REFIID riid, void **obj) { + struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface); + TRACE("iface %p, riid %s, obj %p.\n", iface, debugstr_guid(riid), obj);
if (IsEqualIID(riid, &IID_IMFFinalizableMediaSink) || @@ -370,6 +383,10 @@ static HRESULT WINAPI media_sink_QueryInterface(IMFFinalizableMediaSink *iface, { *obj = iface; } + else if (IsEqualGUID(riid, &IID_IMFMediaEventGenerator)) + { + *obj = &media_sink->IMFMediaEventGenerator_iface; + } else { WARN("Unsupported interface %s.\n", debugstr_guid(riid)); @@ -400,6 +417,7 @@ static ULONG WINAPI media_sink_Release(IMFFinalizableMediaSink *iface) if (!refcount) { IMFFinalizableMediaSink_Shutdown(iface); + IMFMediaEventQueue_Release(media_sink->event_queue); IMFByteStream_Release(media_sink->bytestream); media_sink->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&media_sink->cs); @@ -513,6 +531,7 @@ static HRESULT WINAPI media_sink_Shutdown(IMFFinalizableMediaSink *iface) IMFStreamSink_Release(&stream_sink->IMFStreamSink_iface); }
+ IMFMediaEventQueue_Shutdown(media_sink->event_queue); IMFByteStream_Close(media_sink->bytestream);
media_sink->shutdown = TRUE; @@ -554,9 +573,79 @@ static const IMFFinalizableMediaSinkVtbl media_sink_vtbl = media_sink_EndFinalize, };
+static HRESULT WINAPI media_sink_event_QueryInterface(IMFMediaEventGenerator *iface, REFIID riid, void **obj) +{ + struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface); + return IMFFinalizableMediaSink_QueryInterface(&media_sink->IMFFinalizableMediaSink_iface, riid, obj); +} + +static ULONG WINAPI media_sink_event_AddRef(IMFMediaEventGenerator *iface) +{ + struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface); + return IMFFinalizableMediaSink_AddRef(&media_sink->IMFFinalizableMediaSink_iface); +} + +static ULONG WINAPI media_sink_event_Release(IMFMediaEventGenerator *iface) +{ + struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface); + return IMFFinalizableMediaSink_Release(&media_sink->IMFFinalizableMediaSink_iface); +} + +static HRESULT WINAPI media_sink_event_GetEvent(IMFMediaEventGenerator *iface, DWORD flags, IMFMediaEvent **event) +{ + struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface); + + TRACE("iface %p, flags %#lx, event %p.\n", iface, flags, event); + + return IMFMediaEventQueue_GetEvent(media_sink->event_queue, flags, event); +} + +static HRESULT WINAPI media_sink_event_BeginGetEvent(IMFMediaEventGenerator *iface, IMFAsyncCallback *callback, + IUnknown *state) +{ + struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface); + + TRACE("iface %p, callback %p, state %p.\n", iface, callback, state); + + return IMFMediaEventQueue_BeginGetEvent(media_sink->event_queue, callback, state); +} + +static HRESULT WINAPI media_sink_event_EndGetEvent(IMFMediaEventGenerator *iface, IMFAsyncResult *result, + IMFMediaEvent **event) +{ + struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface); + + TRACE("iface %p, result %p, event %p.\n", iface, result, event); + + return IMFMediaEventQueue_EndGetEvent(media_sink->event_queue, result, event); +} + +static HRESULT WINAPI media_sink_event_QueueEvent(IMFMediaEventGenerator *iface, MediaEventType event_type, + REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) +{ + struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(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(media_sink->event_queue, event_type, ext_type, hr, value); +} + +static const IMFMediaEventGeneratorVtbl media_sink_event_vtbl = +{ + media_sink_event_QueryInterface, + media_sink_event_AddRef, + media_sink_event_Release, + media_sink_event_GetEvent, + media_sink_event_BeginGetEvent, + media_sink_event_EndGetEvent, + media_sink_event_QueueEvent, +}; + static HRESULT media_sink_create(IMFByteStream *bytestream, struct media_sink **out) { struct media_sink *media_sink; + HRESULT hr;
TRACE("bytestream %p, out %p.\n", bytestream, out);
@@ -566,7 +655,14 @@ static HRESULT media_sink_create(IMFByteStream *bytestream, struct media_sink ** if (!(media_sink = calloc(1, sizeof(*media_sink)))) return E_OUTOFMEMORY;
+ if (FAILED(hr = MFCreateEventQueue(&media_sink->event_queue))) + { + free(media_sink); + return hr; + } + media_sink->IMFFinalizableMediaSink_iface.lpVtbl = &media_sink_vtbl; + media_sink->IMFMediaEventGenerator_iface.lpVtbl = &media_sink_event_vtbl; media_sink->refcount = 1; InitializeCriticalSection(&media_sink->cs); media_sink->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs");
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/media_sink.c | 76 +++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+)
diff --git a/dlls/winegstreamer/media_sink.c b/dlls/winegstreamer/media_sink.c index 7ef57c3aa22..638d8e66867 100644 --- a/dlls/winegstreamer/media_sink.c +++ b/dlls/winegstreamer/media_sink.c @@ -44,6 +44,7 @@ struct media_sink { IMFFinalizableMediaSink IMFFinalizableMediaSink_iface; IMFMediaEventGenerator IMFMediaEventGenerator_iface; + IMFClockStateSink IMFClockStateSink_iface; LONG refcount; CRITICAL_SECTION cs; bool shutdown; @@ -74,6 +75,11 @@ static struct media_sink *impl_from_IMFMediaEventGenerator(IMFMediaEventGenerato return CONTAINING_RECORD(iface, struct media_sink, IMFMediaEventGenerator_iface); }
+static struct media_sink *impl_from_IMFClockStateSink(IMFClockStateSink *iface) +{ + return CONTAINING_RECORD(iface, struct media_sink, IMFClockStateSink_iface); +} + static HRESULT WINAPI stream_sink_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj) { struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); @@ -387,6 +393,10 @@ static HRESULT WINAPI media_sink_QueryInterface(IMFFinalizableMediaSink *iface, { *obj = &media_sink->IMFMediaEventGenerator_iface; } + else if (IsEqualIID(riid, &IID_IMFClockStateSink)) + { + *obj = &media_sink->IMFClockStateSink_iface; + } else { WARN("Unsupported interface %s.\n", debugstr_guid(riid)); @@ -642,6 +652,71 @@ static const IMFMediaEventGeneratorVtbl media_sink_event_vtbl = media_sink_event_QueueEvent, };
+static HRESULT WINAPI media_sink_clock_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj) +{ + struct media_sink *media_sink = impl_from_IMFClockStateSink(iface); + return IMFFinalizableMediaSink_QueryInterface(&media_sink->IMFFinalizableMediaSink_iface, riid, obj); +} + +static ULONG WINAPI media_sink_clock_sink_AddRef(IMFClockStateSink *iface) +{ + struct media_sink *media_sink = impl_from_IMFClockStateSink(iface); + return IMFFinalizableMediaSink_AddRef(&media_sink->IMFFinalizableMediaSink_iface); +} + +static ULONG WINAPI media_sink_clock_sink_Release(IMFClockStateSink *iface) +{ + struct media_sink *media_sink = impl_from_IMFClockStateSink(iface); + return IMFFinalizableMediaSink_Release(&media_sink->IMFFinalizableMediaSink_iface); +} + +static HRESULT WINAPI media_sink_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset) +{ + FIXME("iface %p, systime %s, offset %s stub!\n", iface, debugstr_time(systime), debugstr_time(offset)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_sink_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime) +{ + FIXME("iface %p, systime %s stub!\n", iface, debugstr_time(systime)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_sink_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime) +{ + FIXME("%p, %s stub!\n", iface, debugstr_time(systime)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_sink_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime) +{ + FIXME("iface %p, systime %s stub!\n", iface, debugstr_time(systime)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_sink_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME systime, float rate) +{ + FIXME("iface %p, systime %s, rate %f stub!\n", iface, debugstr_time(systime), rate); + + return E_NOTIMPL; +} + +static const IMFClockStateSinkVtbl media_sink_clock_sink_vtbl = +{ + media_sink_clock_sink_QueryInterface, + media_sink_clock_sink_AddRef, + media_sink_clock_sink_Release, + media_sink_clock_sink_OnClockStart, + media_sink_clock_sink_OnClockStop, + media_sink_clock_sink_OnClockPause, + media_sink_clock_sink_OnClockRestart, + media_sink_clock_sink_OnClockSetRate, +}; + static HRESULT media_sink_create(IMFByteStream *bytestream, struct media_sink **out) { struct media_sink *media_sink; @@ -663,6 +738,7 @@ static HRESULT media_sink_create(IMFByteStream *bytestream, struct media_sink **
media_sink->IMFFinalizableMediaSink_iface.lpVtbl = &media_sink_vtbl; media_sink->IMFMediaEventGenerator_iface.lpVtbl = &media_sink_event_vtbl; + media_sink->IMFClockStateSink_iface.lpVtbl = &media_sink_clock_sink_vtbl; media_sink->refcount = 1; InitializeCriticalSection(&media_sink->cs); media_sink->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs");
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/media_sink.c | 296 ++++++++++++++++++++++++++++++-- 1 file changed, 285 insertions(+), 11 deletions(-)
diff --git a/dlls/winegstreamer/media_sink.c b/dlls/winegstreamer/media_sink.c index 638d8e66867..95f4870931e 100644 --- a/dlls/winegstreamer/media_sink.c +++ b/dlls/winegstreamer/media_sink.c @@ -26,6 +26,21 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+enum async_op +{ + ASYNC_START, + ASYNC_STOP, + ASYNC_PAUSE, +}; + +struct async_command +{ + IUnknown IUnknown_iface; + LONG refcount; + + enum async_op op; +}; + struct stream_sink { IMFStreamSink IMFStreamSink_iface; @@ -45,9 +60,18 @@ struct media_sink IMFFinalizableMediaSink IMFFinalizableMediaSink_iface; IMFMediaEventGenerator IMFMediaEventGenerator_iface; IMFClockStateSink IMFClockStateSink_iface; + IMFAsyncCallback async_callback; LONG refcount; CRITICAL_SECTION cs; - bool shutdown; + + enum + { + STATE_OPENED, + STATE_STARTED, + STATE_STOPPED, + STATE_PAUSED, + STATE_SHUTDOWN, + } state;
IMFByteStream *bytestream; IMFMediaEventQueue *event_queue; @@ -80,6 +104,71 @@ static struct media_sink *impl_from_IMFClockStateSink(IMFClockStateSink *iface) return CONTAINING_RECORD(iface, struct media_sink, IMFClockStateSink_iface); }
+static struct media_sink *impl_from_async_callback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct media_sink, async_callback); +} + +static struct async_command *impl_from_async_command_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct async_command, IUnknown_iface); +} + +static HRESULT WINAPI async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IUnknown_AddRef(iface); + return S_OK; + } + + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI async_command_AddRef(IUnknown *iface) +{ + struct async_command *command = impl_from_async_command_IUnknown(iface); + return InterlockedIncrement(&command->refcount); +} + +static ULONG WINAPI async_command_Release(IUnknown *iface) +{ + struct async_command *command = impl_from_async_command_IUnknown(iface); + ULONG refcount = InterlockedDecrement(&command->refcount); + + if (!refcount) + free(command); + + return refcount; +} + +static const IUnknownVtbl async_command_vtbl = +{ + async_command_QueryInterface, + async_command_AddRef, + async_command_Release, +}; + +static HRESULT async_command_create(enum async_op op, struct async_command **out) +{ + struct async_command *command; + + if (!(command = calloc(1, sizeof(*command)))) + return E_OUTOFMEMORY; + + command->IUnknown_iface.lpVtbl = &async_command_vtbl; + command->refcount = 1; + command->op = op; + + TRACE("Created async command %p.\n", command); + *out = command; + + return S_OK; +} + static HRESULT WINAPI stream_sink_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj) { struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); @@ -377,6 +466,73 @@ static struct stream_sink *media_sink_get_stream_sink_by_id(struct media_sink *m return NULL; }
+static HRESULT media_sink_queue_command(struct media_sink *media_sink, enum async_op op) +{ + struct async_command *command; + HRESULT hr; + + if (media_sink->state == STATE_SHUTDOWN) + return MF_E_SHUTDOWN; + + if (FAILED(hr = async_command_create(op, &command))) + return hr; + + return MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &media_sink->async_callback, &command->IUnknown_iface); +} + +static HRESULT media_sink_queue_stream_event(struct media_sink *media_sink, MediaEventType type) +{ + struct stream_sink *stream_sink; + HRESULT hr; + + LIST_FOR_EACH_ENTRY(stream_sink, &media_sink->stream_sinks, struct stream_sink, entry) + { + if (FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream_sink->event_queue, type, &GUID_NULL, S_OK, NULL))) + return hr; + } + + return S_OK; +} + +static HRESULT media_sink_start(struct media_sink *media_sink) +{ + HRESULT hr; + + EnterCriticalSection(&media_sink->cs); + + media_sink->state = STATE_STARTED; + hr = media_sink_queue_stream_event(media_sink, MEStreamSinkStarted); + + LeaveCriticalSection(&media_sink->cs); + return hr; +} + +static HRESULT media_sink_stop(struct media_sink *media_sink) +{ + HRESULT hr; + + EnterCriticalSection(&media_sink->cs); + + media_sink->state = STATE_STOPPED; + hr = media_sink_queue_stream_event(media_sink, MEStreamSinkStopped); + + LeaveCriticalSection(&media_sink->cs); + return hr; +} + +static HRESULT media_sink_pause(struct media_sink *media_sink) +{ + HRESULT hr; + + EnterCriticalSection(&media_sink->cs); + + media_sink->state = STATE_PAUSED; + hr = media_sink_queue_stream_event(media_sink, MEStreamSinkPaused); + + LeaveCriticalSection(&media_sink->cs); + return hr; +} + static HRESULT WINAPI media_sink_QueryInterface(IMFFinalizableMediaSink *iface, REFIID riid, void **obj) { struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface); @@ -528,7 +684,7 @@ static HRESULT WINAPI media_sink_Shutdown(IMFFinalizableMediaSink *iface)
EnterCriticalSection(&media_sink->cs);
- if (media_sink->shutdown) + if (media_sink->state == STATE_SHUTDOWN) { LeaveCriticalSection(&media_sink->cs); return MF_E_SHUTDOWN; @@ -544,7 +700,7 @@ static HRESULT WINAPI media_sink_Shutdown(IMFFinalizableMediaSink *iface) IMFMediaEventQueue_Shutdown(media_sink->event_queue); IMFByteStream_Close(media_sink->bytestream);
- media_sink->shutdown = TRUE; + media_sink->state = STATE_SHUTDOWN;
LeaveCriticalSection(&media_sink->cs);
@@ -672,30 +828,62 @@ static ULONG WINAPI media_sink_clock_sink_Release(IMFClockStateSink *iface)
static HRESULT WINAPI media_sink_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset) { - FIXME("iface %p, systime %s, offset %s stub!\n", iface, debugstr_time(systime), debugstr_time(offset)); + struct media_sink *media_sink = impl_from_IMFClockStateSink(iface); + HRESULT hr;
- return E_NOTIMPL; + TRACE("iface %p, systime %s, offset %s.\n", iface, debugstr_time(systime), debugstr_time(offset)); + + EnterCriticalSection(&media_sink->cs); + + hr = media_sink_queue_command(media_sink, ASYNC_START); + + LeaveCriticalSection(&media_sink->cs); + return hr; }
static HRESULT WINAPI media_sink_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime) { - FIXME("iface %p, systime %s stub!\n", iface, debugstr_time(systime)); + struct media_sink *media_sink = impl_from_IMFClockStateSink(iface); + HRESULT hr;
- return E_NOTIMPL; + TRACE("iface %p, systime %s.\n", iface, debugstr_time(systime)); + + EnterCriticalSection(&media_sink->cs); + + hr = media_sink_queue_command(media_sink, ASYNC_STOP); + + LeaveCriticalSection(&media_sink->cs); + return hr; }
static HRESULT WINAPI media_sink_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime) { - FIXME("%p, %s stub!\n", iface, debugstr_time(systime)); + struct media_sink *media_sink = impl_from_IMFClockStateSink(iface); + HRESULT hr;
- return E_NOTIMPL; + TRACE("iface %p, systime %s.\n", iface, debugstr_time(systime)); + + EnterCriticalSection(&media_sink->cs); + + hr = media_sink_queue_command(media_sink, ASYNC_PAUSE); + + LeaveCriticalSection(&media_sink->cs); + return hr; }
static HRESULT WINAPI media_sink_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime) { - FIXME("iface %p, systime %s stub!\n", iface, debugstr_time(systime)); + struct media_sink *media_sink = impl_from_IMFClockStateSink(iface); + HRESULT hr;
- return E_NOTIMPL; + TRACE("iface %p, systime %s.\n", iface, debugstr_time(systime)); + + EnterCriticalSection(&media_sink->cs); + + hr = media_sink_queue_command(media_sink, ASYNC_START); + + LeaveCriticalSection(&media_sink->cs); + return hr; }
static HRESULT WINAPI media_sink_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME systime, float rate) @@ -717,6 +905,90 @@ static const IMFClockStateSinkVtbl media_sink_clock_sink_vtbl = media_sink_clock_sink_OnClockSetRate, };
+static HRESULT WINAPI media_sink_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) +{ + TRACE("iface %p, riid %s, obj %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFAsyncCallback) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFAsyncCallback_AddRef(iface); + return S_OK; + } + + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI media_sink_callback_AddRef(IMFAsyncCallback *iface) +{ + struct media_sink *sink = impl_from_async_callback(iface); + return IMFFinalizableMediaSink_AddRef(&sink->IMFFinalizableMediaSink_iface); +} + +static ULONG WINAPI media_sink_callback_Release(IMFAsyncCallback *iface) +{ + struct media_sink *sink = impl_from_async_callback(iface); + return IMFFinalizableMediaSink_Release(&sink->IMFFinalizableMediaSink_iface); +} + +static HRESULT WINAPI media_sink_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +{ + TRACE("iface %p, flags %p, queue %p.\n", iface, flags, queue); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_sink_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *async_result) +{ + struct media_sink *media_sink = impl_from_async_callback(iface); + struct async_command *command; + HRESULT hr = E_FAIL; + IUnknown *state; + + TRACE("iface %p, async_result %p.\n", iface, async_result); + + EnterCriticalSection(&media_sink->cs); + + if (!(state = IMFAsyncResult_GetStateNoAddRef(async_result))) + { + LeaveCriticalSection(&media_sink->cs); + return hr; + } + + command = impl_from_async_command_IUnknown(state); + switch (command->op) + { + case ASYNC_START: + hr = media_sink_start(media_sink); + break; + case ASYNC_STOP: + hr = media_sink_stop(media_sink); + break; + case ASYNC_PAUSE: + hr = media_sink_pause(media_sink); + break; + default: + WARN("Unsupported op %u.\n", command->op); + break; + } + + LeaveCriticalSection(&media_sink->cs); + + return hr; +} + +static const IMFAsyncCallbackVtbl media_sink_callback_vtbl = +{ + media_sink_callback_QueryInterface, + media_sink_callback_AddRef, + media_sink_callback_Release, + media_sink_callback_GetParameters, + media_sink_callback_Invoke, +}; + static HRESULT media_sink_create(IMFByteStream *bytestream, struct media_sink **out) { struct media_sink *media_sink; @@ -739,7 +1011,9 @@ static HRESULT media_sink_create(IMFByteStream *bytestream, struct media_sink ** media_sink->IMFFinalizableMediaSink_iface.lpVtbl = &media_sink_vtbl; media_sink->IMFMediaEventGenerator_iface.lpVtbl = &media_sink_event_vtbl; media_sink->IMFClockStateSink_iface.lpVtbl = &media_sink_clock_sink_vtbl; + media_sink->async_callback.lpVtbl = &media_sink_callback_vtbl; media_sink->refcount = 1; + media_sink->state = STATE_OPENED; InitializeCriticalSection(&media_sink->cs); media_sink->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs"); IMFByteStream_AddRef((media_sink->bytestream = bytestream));
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/media_sink.c:
TRACE("iface %p, stream_sink_id %#lx, media_type %p, stream_sink %p.\n", iface, stream_sink_id, media_type, stream_sink);
- EnterCriticalSection(&media_sink->cs);
- if (media_sink_get_stream_sink_by_id(media_sink, stream_sink_id)) return MF_E_STREAMSINK_EXISTS;
You'll need to leave the CS on the error path now.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/media_sink.c:
IMFMediaType *type; IMFFinalizableMediaSink *media_sink;
- IMFMediaEventQueue *event_queue;
To the contrary to what the commit message says, you're not actually implementing an IMFMediaEventGenerator interface here, although you probably could?
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/media_sink.c:
- HRESULT hr;
- LIST_FOR_EACH_ENTRY(stream_sink, &media_sink->stream_sinks, struct stream_sink, entry)
- {
if (FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream_sink->event_queue, type, &GUID_NULL, S_OK, NULL)))
return hr;
- }
- return S_OK;
+}
+static HRESULT media_sink_start(struct media_sink *media_sink) +{
- HRESULT hr;
- EnterCriticalSection(&media_sink->cs);
As these are called from the callback Invoke which already enters the CS, I think you could assume it's entered already?
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/media_sink.c:
- HRESULT hr;
- EnterCriticalSection(&media_sink->cs);
- media_sink->state = STATE_STARTED;
- hr = media_sink_queue_stream_event(media_sink, MEStreamSinkStarted);
- LeaveCriticalSection(&media_sink->cs);
- return hr;
+}
+static HRESULT media_sink_stop(struct media_sink *media_sink) +{
- HRESULT hr;
- EnterCriticalSection(&media_sink->cs);
Same here and below for media_sink_pause.
On Thu Aug 10 07:41:00 2023 +0000, Rémi Bernon wrote:
To the contrary to what the commit message says, you're not actually implementing an IMFMediaEventGenerator interface here, although you probably could?
Maybe I should change the commit message? Any suggestions?
On Thu Aug 10 08:03:41 2023 +0000, Ziqing Hui wrote:
Maybe I should change the commit message? Any suggestions?
How about "Add event queue to stream sink."
On Thu Aug 10 08:10:09 2023 +0000, Ziqing Hui wrote:
How about "Add event queue to stream sink."
Why not implement a IMFMediaEventGenerator interface for the stream? I think it's supposed to implement it as well (even though it has dedicated methods already to get the events).
On Thu Aug 10 08:33:41 2023 +0000, Rémi Bernon wrote:
Why not implement a IMFMediaEventGenerator interface for the stream? I think it's supposed to implement it as well (even though it has dedicated methods already to get the events).
Well.. I'm kind of confused by what your "implement IMFMediaEventGenerator interface" means here. IMFStreamSink interface inherits from IMFMediaEventGenerator. So I thought implment stream_sink_{GetEvent,BeginGetEvent,EndGetEvent,QueueEvent} is "implement IMFMediaEventGenerator interface", isn't that true?
On Thu Aug 10 08:41:42 2023 +0000, Ziqing Hui wrote:
Well.. I'm kind of confused by what your "implement IMFMediaEventGenerator interface" means here. IMFStreamSink interface inherits from IMFMediaEventGenerator. So I thought implment stream_sink_{GetEvent,BeginGetEvent,EndGetEvent,QueueEvent} is "implement IMFMediaEventGenerator interface", isn't that true?
Oh my bad, I didn't realize it was deriving from it. All good then.