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.
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 2 + dlls/winegstreamer/media_sink.c | 282 +++++++++++++++++++++++++++++++ 3 files changed, 285 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/media_sink.c b/dlls/winegstreamer/media_sink.c new file mode 100644 index 00000000000..d7d24c2235a --- /dev/null +++ b/dlls/winegstreamer/media_sink.c @@ -0,0 +1,282 @@ +/* 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); + 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; +}
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/media_sink.c | 291 +++++++++++++++++++++++++++++++- 1 file changed, 288 insertions(+), 3 deletions(-)
diff --git a/dlls/winegstreamer/media_sink.c b/dlls/winegstreamer/media_sink.c index d7d24c2235a..57f38729bbb 100644 --- a/dlls/winegstreamer/media_sink.c +++ b/dlls/winegstreamer/media_sink.c @@ -19,11 +19,23 @@
#include "gst_private.h" #include "mferror.h" +#include "mfapi.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+struct stream_sink +{ + IMFStreamSink IMFStreamSink_iface; + LONG refcount; + DWORD id; + + IMFMediaType *type; + IMFMediaEventQueue *event_queue; + struct media_sink *media_sink; +}; + struct media_sink { IMFFinalizableMediaSink IMFFinalizableMediaSink_iface; @@ -32,13 +44,225 @@ struct media_sink bool shutdown;
IMFByteStream *bytestream; + + struct stream_sink **stream_sinks; + size_t stream_sink_count; + size_t stream_sink_size; };
+static struct stream_sink *impl_from_IMFStreamSink(IMFStreamSink *iface) +{ + return CONTAINING_RECORD(iface, struct stream_sink, IMFStreamSink_iface); +} + static struct media_sink *impl_from_IMFFinalizableMediaSink(IMFFinalizableMediaSink *iface) { return CONTAINING_RECORD(iface, struct media_sink, IMFFinalizableMediaSink_iface); }
+static HRESULT WINAPI stream_sink_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj) +{ + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + + TRACE("iface %p, riid %s, obj %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFStreamSink) || + IsEqualGUID(riid, &IID_IMFMediaEventGenerator) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = &stream_sink->IMFStreamSink_iface; + } + else + { + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*obj); + + return S_OK; +} + +static ULONG WINAPI stream_sink_AddRef(IMFStreamSink *iface) +{ + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + ULONG refcount = InterlockedIncrement(&stream_sink->refcount); + TRACE("iface %p, refcount %lu.\n", iface, refcount); + return refcount; +} + +static ULONG WINAPI stream_sink_Release(IMFStreamSink *iface) +{ + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + ULONG refcount = InterlockedDecrement(&stream_sink->refcount); + + TRACE("iface %p, refcount %lu.\n", iface, refcount); + + if (!refcount) + { + IMFMediaEventQueue_Release(stream_sink->event_queue); + IMFFinalizableMediaSink_Release(&stream_sink->media_sink->IMFFinalizableMediaSink_iface); + IMFMediaType_Release(stream_sink->type); + free(stream_sink); + } + + return refcount; +} + +static HRESULT WINAPI stream_sink_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event) +{ + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + + TRACE("iface %p, flags %#lx, event %p.\n", iface, flags, event); + + return IMFMediaEventQueue_GetEvent(stream_sink->event_queue, flags, event); +} + +static HRESULT WINAPI stream_sink_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback, + IUnknown *state) +{ + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + + TRACE("iface %p, callback %p, state %p.\n", iface, callback, state); + + return IMFMediaEventQueue_BeginGetEvent(stream_sink->event_queue, callback, state); +} + +static HRESULT WINAPI stream_sink_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result, + IMFMediaEvent **event) +{ + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + + TRACE("iface %p, result %p, event %p.\n", iface, result, event); + + return IMFMediaEventQueue_EndGetEvent(stream_sink->event_queue, result, event); +} + +static HRESULT WINAPI stream_sink_QueueEvent(IMFStreamSink *iface, MediaEventType event_type, + REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) +{ + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + + TRACE("iface %p, event_type %lu, ext_type %s, hr %#lx, value %p.\n", + iface, event_type, debugstr_guid(ext_type), hr, value); + + return IMFMediaEventQueue_QueueEventParamVar(stream_sink->event_queue, event_type, ext_type, hr, value); +} + +static HRESULT WINAPI stream_sink_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **ret) +{ + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + + TRACE("iface %p, ret %p.\n", iface, ret); + + *ret = (IMFMediaSink *)&stream_sink->media_sink->IMFFinalizableMediaSink_iface; + + return S_OK; +} + +static HRESULT WINAPI stream_sink_GetIdentifier(IMFStreamSink *iface, DWORD *identifier) +{ + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + + TRACE("iface %p, identifier %p.\n", iface, identifier); + + *identifier = stream_sink->id; + + return S_OK; +} + +static HRESULT WINAPI stream_sink_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler) +{ + FIXME("iface %p, handler %p stub!\n", iface, handler); + + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_sink_ProcessSample(IMFStreamSink *iface, IMFSample *sample) +{ + FIXME("iface %p, sample %p stub!\n", iface, sample); + + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_sink_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type, + const PROPVARIANT *marker_value, const PROPVARIANT *context_value) +{ + FIXME("iface %p, marker_type %d, marker_value %p, context_value %p stub!\n", + iface, marker_type, marker_value, context_value); + + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_sink_Flush(IMFStreamSink *iface) +{ + FIXME("iface %p stub!\n", iface); + + return E_NOTIMPL; +} + +static const IMFStreamSinkVtbl stream_sink_vtbl = +{ + stream_sink_QueryInterface, + stream_sink_AddRef, + stream_sink_Release, + stream_sink_GetEvent, + stream_sink_BeginGetEvent, + stream_sink_EndGetEvent, + stream_sink_QueueEvent, + stream_sink_GetMediaSink, + stream_sink_GetIdentifier, + stream_sink_GetMediaTypeHandler, + stream_sink_ProcessSample, + stream_sink_PlaceMarker, + stream_sink_Flush, +}; + +static HRESULT stream_sink_create(DWORD stream_sink_id, IMFMediaType *media_type, struct media_sink *media_sink, + struct stream_sink **out) +{ + struct stream_sink *stream_sink; + HRESULT hr; + + TRACE("stream_sink_id %#lx, media_type %p, media_sink %p, out %p.\n", + stream_sink_id, media_type, media_sink, out); + + if (!(stream_sink = calloc(1, sizeof(*stream_sink)))) + return E_OUTOFMEMORY; + + if (FAILED(hr = MFCreateEventQueue(&stream_sink->event_queue))) + { + free(stream_sink); + return hr; + } + + stream_sink->IMFStreamSink_iface.lpVtbl = &stream_sink_vtbl; + stream_sink->refcount = 1; + stream_sink->id = stream_sink_id; + IMFMediaType_AddRef(stream_sink->type = media_type); + stream_sink->media_sink = media_sink; + IMFFinalizableMediaSink_AddRef(&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) +{ + size_t i; + + for (i = 0; i < media_sink->stream_sink_count; ++i) + { + if (media_sink->stream_sinks[i]->id == id) + return media_sink->stream_sinks[i]; + } + + 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); @@ -96,10 +320,41 @@ static HRESULT WINAPI media_sink_GetCharacteristics(IMFFinalizableMediaSink *ifa static HRESULT WINAPI media_sink_AddStreamSink(IMFFinalizableMediaSink *iface, DWORD stream_sink_id, IMFMediaType *media_type, IMFStreamSink **stream_sink) { - FIXME("iface %p, stream_sink_id %#lx, media_type %p, stream_sink %p stub!\n", + struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface); + struct stream_sink *object; + HRESULT hr; + + TRACE("iface %p, stream_sink_id %#lx, media_type %p, stream_sink %p.\n", iface, stream_sink_id, media_type, stream_sink);
- return E_NOTIMPL; + if (!media_type) + return E_POINTER; + if (media_sink_get_stream_sink_by_id(media_sink, stream_sink_id)) + return MF_E_STREAMSINK_EXISTS; + + if (FAILED(hr = stream_sink_create(stream_sink_id, media_type, media_sink, &object))) + { + WARN("Failed to create stream sink, hr %#lx.\n", hr); + return hr; + } + + EnterCriticalSection(&media_sink->cs); + + if (!array_reserve((void **)&media_sink->stream_sinks, + &media_sink->stream_sink_size, media_sink->stream_sink_count + 1, sizeof(*object))) + { + IMFStreamSink_Release(&object->IMFStreamSink_iface); + LeaveCriticalSection(&media_sink->cs); + return E_OUTOFMEMORY; + } + media_sink->stream_sinks[media_sink->stream_sink_count++] = object; + + 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) @@ -149,6 +404,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); + unsigned int i;
TRACE("iface %p.\n", iface);
@@ -160,6 +416,14 @@ static HRESULT WINAPI media_sink_Shutdown(IMFFinalizableMediaSink *iface) return MF_E_SHUTDOWN; }
+ for (i = 0; i < media_sink->stream_sink_count; ++i) + { + struct stream_sink *stream_sink = media_sink->stream_sinks[i]; + IMFMediaEventQueue_Shutdown(stream_sink->event_queue); + IMFStreamSink_Release(&stream_sink->IMFStreamSink_iface); + } + free(media_sink->stream_sinks); + IMFByteStream_Close(media_sink->bytestream);
media_sink->shutdown = TRUE; @@ -252,6 +516,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;
@@ -260,8 +525,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 | 92 +++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+)
diff --git a/dlls/winegstreamer/media_sink.c b/dlls/winegstreamer/media_sink.c index 57f38729bbb..c9560a7ecb0 100644 --- a/dlls/winegstreamer/media_sink.c +++ b/dlls/winegstreamer/media_sink.c @@ -39,11 +39,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 stream_sink **stream_sinks; size_t stream_sink_count; @@ -60,6 +62,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); @@ -265,6 +272,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) || @@ -273,6 +282,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)); @@ -303,6 +316,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); free(media_sink); } @@ -424,6 +438,7 @@ static HRESULT WINAPI media_sink_Shutdown(IMFFinalizableMediaSink *iface) } free(media_sink->stream_sinks);
+ IMFMediaEventQueue_Shutdown(media_sink->event_queue); IMFByteStream_Close(media_sink->bytestream);
media_sink->shutdown = TRUE; @@ -465,9 +480,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);
@@ -477,7 +562,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 c9560a7ecb0..290a923d310 100644 --- a/dlls/winegstreamer/media_sink.c +++ b/dlls/winegstreamer/media_sink.c @@ -40,6 +40,7 @@ struct media_sink { IMFFinalizableMediaSink IMFFinalizableMediaSink_iface; IMFMediaEventGenerator IMFMediaEventGenerator_iface; + IMFClockStateSink IMFClockStateSink_iface; LONG refcount; CRITICAL_SECTION cs; bool shutdown; @@ -67,6 +68,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); @@ -286,6 +292,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)); @@ -549,6 +559,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; @@ -570,6 +645,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 | 308 ++++++++++++++++++++++++++++++-- 1 file changed, 297 insertions(+), 11 deletions(-)
diff --git a/dlls/winegstreamer/media_sink.c b/dlls/winegstreamer/media_sink.c index 290a923d310..b5dee71370b 100644 --- a/dlls/winegstreamer/media_sink.c +++ b/dlls/winegstreamer/media_sink.c @@ -25,6 +25,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; @@ -41,12 +56,22 @@ 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; + DWORD async_queue;
struct stream_sink **stream_sinks; size_t stream_sink_count; @@ -73,6 +98,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); @@ -276,6 +366,74 @@ 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(media_sink->async_queue, &media_sink->async_callback, &command->IUnknown_iface); +} + +static HRESULT media_sink_queue_stream_event(struct media_sink *media_sink, MediaEventType type) +{ + HRESULT hr; + size_t i; + + for (i = 0; i < media_sink->stream_sink_count; ++i) + { + struct stream_sink *stream_sink = media_sink->stream_sinks[i]; + 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); @@ -434,7 +592,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; @@ -448,10 +606,11 @@ static HRESULT WINAPI media_sink_Shutdown(IMFFinalizableMediaSink *iface) } free(media_sink->stream_sinks);
+ MFUnlockWorkQueue(media_sink->async_queue); IMFMediaEventQueue_Shutdown(media_sink->event_queue); IMFByteStream_Close(media_sink->bytestream);
- media_sink->shutdown = TRUE; + media_sink->state = STATE_SHUTDOWN;
LeaveCriticalSection(&media_sink->cs);
@@ -579,30 +738,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) @@ -624,6 +815,92 @@ 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; + IUnknown *state; + HRESULT hr; + + TRACE("iface %p, async_result %p.\n", iface, async_result); + + EnterCriticalSection(&media_sink->cs); + + if (FAILED(hr = IMFAsyncResult_GetState(async_result, &state))) + { + 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); + + IUnknown_Release(state); + + 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; @@ -643,10 +920,19 @@ static HRESULT media_sink_create(IMFByteStream *bytestream, struct media_sink ** return hr; }
+ if (FAILED(hr = MFAllocateWorkQueue(&media_sink->async_queue))) + { + IMFMediaEventQueue_Release(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->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/gst_private.h:
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);
You're not using it anywhere, so the code is actually dead code, please add a use.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/media_sink.c:
+{
- 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);
```suggestion:-0+0 IMFByteStream_AddRef((media_sink->bytestream = bytestream)); ```
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/media_sink.c:
- 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);
You need to destroy the CS here.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/media_sink.c:
bool shutdown; IMFByteStream *bytestream;
- struct stream_sink **stream_sinks;
- size_t stream_sink_count;
- size_t stream_sink_size;
I'd personally use a `struct list`, there's only going to be a few elements, and iterating doesn't need to be optimised.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/media_sink.c:
+{
- struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface);
- TRACE("iface %p, event_type %lu, ext_type %s, hr %#lx, value %p.\n",
iface, event_type, debugstr_guid(ext_type), hr, value);
- return IMFMediaEventQueue_QueueEventParamVar(stream_sink->event_queue, event_type, ext_type, hr, value);
+}
+static HRESULT WINAPI stream_sink_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **ret) +{
- struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface);
- TRACE("iface %p, ret %p.\n", iface, ret);
- *ret = (IMFMediaSink *)&stream_sink->media_sink->IMFFinalizableMediaSink_iface;
You need to AddRef.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/media_sink.c:
- TRACE("stream_sink_id %#lx, media_type %p, media_sink %p, out %p.\n",
stream_sink_id, media_type, media_sink, out);
- if (!(stream_sink = calloc(1, sizeof(*stream_sink))))
return E_OUTOFMEMORY;
- if (FAILED(hr = MFCreateEventQueue(&stream_sink->event_queue)))
- {
free(stream_sink);
return hr;
- }
- stream_sink->IMFStreamSink_iface.lpVtbl = &stream_sink_vtbl;
- stream_sink->refcount = 1;
- stream_sink->id = stream_sink_id;
- IMFMediaType_AddRef(stream_sink->type = media_type);
```suggestion:-0+0 IMFMediaType_AddRef((stream_sink->type = media_type)); ```
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/media_sink.c:
#include "mferror.h" +#include "mfapi.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+struct stream_sink +{
- IMFStreamSink IMFStreamSink_iface;
- LONG refcount;
- DWORD id;
- IMFMediaType *type;
- IMFMediaEventQueue *event_queue;
- struct media_sink *media_sink;
Imho it's better to use the interface pointer when you are keeping a reference to it. And using the internal struct only when you are holding no reference or a private reference to it.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/media_sink.c:
static HRESULT WINAPI media_sink_AddStreamSink(IMFFinalizableMediaSink *iface, DWORD stream_sink_id, IMFMediaType *media_type, IMFStreamSink **stream_sink) {
- FIXME("iface %p, stream_sink_id %#lx, media_type %p, stream_sink %p stub!\n",
- struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface);
- struct stream_sink *object;
- HRESULT hr;
- TRACE("iface %p, stream_sink_id %#lx, media_type %p, stream_sink %p.\n", iface, stream_sink_id, media_type, stream_sink);
- return E_NOTIMPL;
- if (!media_type)
return E_POINTER;
I think media_type can be NULL, according to MSDN? In which case it's supposed to be set later using the IMFMediaTypeHandler interface. You should probably keep one on the streams (created with `MFCreateSimpleTypeHandler`) instead of a media type.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/media_sink.c:
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))))
```suggestion:-0+0 if (FAILED(hr = async_command_create(op, &command))) ```
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/media_sink.c:
LONG refcount; CRITICAL_SECTION cs;
- bool shutdown;
enum
{
STATE_OPENED,
STATE_STARTED,
STATE_STOPPED,
STATE_PAUSED,
STATE_SHUTDOWN,
} state;
IMFByteStream *bytestream; IMFMediaEventQueue *event_queue;
DWORD async_queue;
Please don't use a custom queue, I know the media source does but it's a mistake and it should (and will) use the standard queues. You can probably use `MFASYNC_CALLBACK_QUEUE_STANDARD` here, or `MFASYNC_CALLBACK_QUEUE_MULTITHREADED`.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/media_sink.c:
- 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;
- IUnknown *state;
- HRESULT hr;
- TRACE("iface %p, async_result %p.\n", iface, async_result);
- EnterCriticalSection(&media_sink->cs);
- if (FAILED(hr = IMFAsyncResult_GetState(async_result, &state)))
Fwiw, you can also use `IMFAsyncResult_GetStateNoAddRef` for a simpler getter, and you won't need to release the reference.
Also, do we have tests for this? I think it'd be nice to have a few basic ones, checking the interfaces presences and so on.
On Wed Aug 9 01:56:16 2023 +0000, Rémi Bernon wrote:
Also, do we have tests for this? I think it'd be nice to have a few basic ones, checking the interfaces presences and so on.
Yep, we have tests for them, see: https://gitlab.winehq.org/wine/wine/-/blob/master/dlls/mf/tests/mf.c#L6755
Also, see !3369
On Tue Aug 8 07:46:52 2023 +0000, Rémi Bernon wrote:
I think media_type can be NULL, according to MSDN? In which case it's supposed to be set later using the IMFMediaTypeHandler interface. You should probably keep one on the streams (created with `MFCreateSimpleTypeHandler`) instead of a media type.
OK, I'll add a IMFMediaTypeHandler interface.
But the tests show that IMFMediaTypeHandler can be queried from stream sink. See: https://gitlab.winehq.org/wine/wine/-/blob/master/dlls/mf/tests/mf.c#L6983