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.
-- v4: 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.
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 | 270 +++++++++++++++++++++++++++++++- 1 file changed, 267 insertions(+), 3 deletions(-)
diff --git a/dlls/winegstreamer/media_sink.c b/dlls/winegstreamer/media_sink.c index 4f60a0955d0..02a5d6d8869 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,36 @@ 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)) + { + LeaveCriticalSection(&media_sink->cs); + 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); + LeaveCriticalSection(&media_sink->cs); + 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 +386,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 +398,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 +462,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 +497,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 +506,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 02a5d6d8869..350caf49e4c 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; @@ -401,6 +418,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 350caf49e4c..45916267ab3 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 45916267ab3..85463e6aab2 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); @@ -517,6 +535,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; @@ -558,9 +577,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);
@@ -570,7 +659,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 85463e6aab2..039b2cb9578 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)); @@ -646,6 +656,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; @@ -667,6 +742,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 | 276 ++++++++++++++++++++++++++++++-- 1 file changed, 265 insertions(+), 11 deletions(-)
diff --git a/dlls/winegstreamer/media_sink.c b/dlls/winegstreamer/media_sink.c index 039b2cb9578..9083dea6709 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,53 @@ 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) +{ + media_sink->state = STATE_STARTED; + return media_sink_queue_stream_event(media_sink, MEStreamSinkStarted); +} + +static HRESULT media_sink_stop(struct media_sink *media_sink) +{ + media_sink->state = STATE_STOPPED; + return media_sink_queue_stream_event(media_sink, MEStreamSinkStopped); + +} + +static HRESULT media_sink_pause(struct media_sink *media_sink) +{ + media_sink->state = STATE_PAUSED; + return media_sink_queue_stream_event(media_sink, MEStreamSinkPaused); +} + static HRESULT WINAPI media_sink_QueryInterface(IMFFinalizableMediaSink *iface, REFIID riid, void **obj) { struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface); @@ -532,7 +668,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; @@ -548,7 +684,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);
@@ -676,30 +812,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) @@ -721,6 +889,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; @@ -743,7 +995,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));
This merge request was approved by Rémi Bernon.