From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- configure | 1 + configure.ac | 1 + dlls/mfsrcsnk/Makefile.in | 1 + dlls/mfsrcsnk/tests/Makefile.in | 5 + dlls/mfsrcsnk/tests/mfsrcsnk.c | 163 ++++++++++ dlls/mfsrcsnk/wave.c | 539 +++++++++++++++++++++++++++++++- 6 files changed, 707 insertions(+), 3 deletions(-) create mode 100644 dlls/mfsrcsnk/tests/Makefile.in create mode 100644 dlls/mfsrcsnk/tests/mfsrcsnk.c
diff --git a/configure b/configure index 41c60f76687..b37a2989db3 100755 --- a/configure +++ b/configure @@ -21573,6 +21573,7 @@ wine_fn_config_makefile dlls/mfplay/tests enable_tests wine_fn_config_makefile dlls/mfreadwrite enable_mfreadwrite wine_fn_config_makefile dlls/mfreadwrite/tests enable_tests wine_fn_config_makefile dlls/mfsrcsnk enable_mfsrcsnk +wine_fn_config_makefile dlls/mfsrcsnk/tests enable_tests wine_fn_config_makefile dlls/mgmtapi enable_mgmtapi wine_fn_config_makefile dlls/midimap enable_midimap wine_fn_config_makefile dlls/mlang enable_mlang diff --git a/configure.ac b/configure.ac index 44b85d5fe26..30a123fcb54 100644 --- a/configure.ac +++ b/configure.ac @@ -2739,6 +2739,7 @@ WINE_CONFIG_MAKEFILE(dlls/mfplay/tests) WINE_CONFIG_MAKEFILE(dlls/mfreadwrite) WINE_CONFIG_MAKEFILE(dlls/mfreadwrite/tests) WINE_CONFIG_MAKEFILE(dlls/mfsrcsnk) +WINE_CONFIG_MAKEFILE(dlls/mfsrcsnk/tests) WINE_CONFIG_MAKEFILE(dlls/mgmtapi) WINE_CONFIG_MAKEFILE(dlls/midimap) WINE_CONFIG_MAKEFILE(dlls/mlang) diff --git a/dlls/mfsrcsnk/Makefile.in b/dlls/mfsrcsnk/Makefile.in index a110a5058f1..8482d8f3556 100644 --- a/dlls/mfsrcsnk/Makefile.in +++ b/dlls/mfsrcsnk/Makefile.in @@ -1,5 +1,6 @@ MODULE = mfsrcsnk.dll IMPORTLIB = mfsrcsnk +IMPORTS = mfplat mfuuid uuid
EXTRADLLFLAGS = -Wb,--prefer-native
diff --git a/dlls/mfsrcsnk/tests/Makefile.in b/dlls/mfsrcsnk/tests/Makefile.in new file mode 100644 index 00000000000..59ee4830573 --- /dev/null +++ b/dlls/mfsrcsnk/tests/Makefile.in @@ -0,0 +1,5 @@ +TESTDLL = mfsrcsnk.dll +IMPORTS = ole32 mfsrcsnk mfplat uuid mfuuid + +C_SRCS = \ + mfsrcsnk.c diff --git a/dlls/mfsrcsnk/tests/mfsrcsnk.c b/dlls/mfsrcsnk/tests/mfsrcsnk.c new file mode 100644 index 00000000000..df3fcfbee38 --- /dev/null +++ b/dlls/mfsrcsnk/tests/mfsrcsnk.c @@ -0,0 +1,163 @@ +/* + * Copyright 2022 Nikolay Sivov 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 <stdarg.h> +#include <string.h> + +#define COBJMACROS + +#include "windef.h" + +#include "mfapi.h" +#include "mfidl.h" +#include "mferror.h" + +#include "wine/test.h" + +#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) +static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported) +{ + IUnknown *iface = iface_ptr; + HRESULT hr, expected_hr; + IUnknown *unk; + + expected_hr = supported ? S_OK : E_NOINTERFACE; + + hr = IUnknown_QueryInterface(iface, iid, (void **)&unk); + ok_(__FILE__, line)(hr == expected_hr, "Got hr %#lx, expected %#lx.\n", hr, expected_hr); + if (SUCCEEDED(hr)) + IUnknown_Release(unk); +} + +static void test_wave_sink(void) +{ + IMFStreamSink *stream_sink; + IMFMediaSink *sink, *sink2; + IMFByteStream *bytestream; + IMFMediaType *media_type; + DWORD id, count, flags; + HRESULT hr; + + hr = MFCreateWAVEMediaSink(NULL, NULL, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateWAVEMediaSink(NULL, NULL, &sink); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, 2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, 2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, 8); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateTempFile(MF_ACCESSMODE_WRITE, MF_OPENMODE_DELETE_IF_EXIST, 0, &bytestream); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateWAVEMediaSink(bytestream, NULL, &sink); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateWAVEMediaSink(bytestream, media_type, &sink); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Sink tests */ + hr = IMFMediaSink_GetCharacteristics(sink, &flags); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(flags == (MEDIASINK_FIXED_STREAMS | MEDIASINK_RATELESS), "Unexpected flags %#lx.\n", flags); + + hr = IMFMediaSink_GetStreamSinkCount(sink, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaSink_GetStreamSinkCount(sink, &count); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(count == 1, "Unexpected count %lu.\n", count); + + hr = IMFMediaSink_AddStreamSink(sink, 123, media_type, &stream_sink); + ok(hr == MF_E_STREAMSINKS_FIXED, "Unexpected hr %#lx.\n", hr); + + check_interface(sink, &IID_IMFMediaEventGenerator, TRUE); + check_interface(sink, &IID_IMFFinalizableMediaSink, TRUE); + + /* Stream tests */ + hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream_sink); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFStreamSink_GetIdentifier(stream_sink, &id); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(id == 1, "Unexpected id %#lx.\n", id); + IMFStreamSink_Release(stream_sink); + + hr = IMFMediaSink_GetStreamSinkById(sink, 0, &stream_sink); + ok(hr == MF_E_INVALIDSTREAMNUMBER, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSink_GetStreamSinkById(sink, id, &stream_sink); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFStreamSink_GetMediaSink(stream_sink, &sink2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaSink_Release(sink2); + + /* Shutdown state */ + hr = IMFMediaSink_Shutdown(sink); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaSink_Shutdown(sink); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + + hr = IMFStreamSink_GetMediaSink(stream_sink, &sink2); + ok(hr == MF_E_STREAMSINK_REMOVED, "Unexpected hr %#lx.\n", hr); + + hr = IMFStreamSink_GetIdentifier(stream_sink, &id); + ok(hr == MF_E_STREAMSINK_REMOVED, "Unexpected hr %#lx.\n", hr); + + IMFStreamSink_Release(stream_sink); + + hr = IMFMediaSink_AddStreamSink(sink, 123, media_type, &stream_sink); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream_sink); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSink_GetStreamSinkById(sink, 0, &stream_sink); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSink_GetCharacteristics(sink, &flags); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + + IMFMediaSink_Release(sink); + + IMFMediaType_Release(media_type); + IMFByteStream_Release(bytestream); +} + +START_TEST(mfsrcsnk) +{ + HRESULT hr; + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + test_wave_sink(); + + hr = MFShutdown(); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); +} diff --git a/dlls/mfsrcsnk/wave.c b/dlls/mfsrcsnk/wave.c index d9d51ac62e2..9f271375e1e 100644 --- a/dlls/mfsrcsnk/wave.c +++ b/dlls/mfsrcsnk/wave.c @@ -16,18 +16,551 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#define COBJMACROS + +#include "mfapi.h" #include "mfidl.h" +#include "mferror.h" + #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+enum wave_sink_flags +{ + SINK_SHUT_DOWN = 0x1, +}; + +struct wave_sink +{ + IMFFinalizableMediaSink IMFFinalizableMediaSink_iface; + IMFMediaEventGenerator IMFMediaEventGenerator_iface; + IMFStreamSink IMFStreamSink_iface; + LONG refcount; + + IMFMediaEventQueue *event_queue; + IMFMediaEventQueue *stream_event_queue; + + IMFByteStream *bytestream; + + unsigned int flags; + CRITICAL_SECTION cs; +}; + +static struct wave_sink *impl_from_IMFFinalizableMediaSink(IMFFinalizableMediaSink *iface) +{ + return CONTAINING_RECORD(iface, struct wave_sink, IMFFinalizableMediaSink_iface); +} + +static struct wave_sink *impl_from_IMFMediaEventGenerator(IMFMediaEventGenerator *iface) +{ + return CONTAINING_RECORD(iface, struct wave_sink, IMFMediaEventGenerator_iface); +} + +static struct wave_sink *impl_from_IMFStreamSink(IMFStreamSink *iface) +{ + return CONTAINING_RECORD(iface, struct wave_sink, IMFStreamSink_iface); +} + +static HRESULT WINAPI wave_sink_QueryInterface(IMFFinalizableMediaSink *iface, REFIID riid, void **obj) +{ + struct wave_sink *sink = impl_from_IMFFinalizableMediaSink(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFFinalizableMediaSink) || + IsEqualIID(riid, &IID_IMFMediaSink) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + } + else if (IsEqualIID(riid, &IID_IMFMediaEventGenerator)) + { + *obj = &sink->IMFMediaEventGenerator_iface; + } + else + { + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*obj); + + return S_OK; +} + +static ULONG WINAPI wave_sink_AddRef(IMFFinalizableMediaSink *iface) +{ + struct wave_sink *sink = impl_from_IMFFinalizableMediaSink(iface); + ULONG refcount = InterlockedIncrement(&sink->refcount); + TRACE("%p, refcount %lu.\n", iface, refcount); + return refcount; +} + +static ULONG WINAPI wave_sink_Release(IMFFinalizableMediaSink *iface) +{ + struct wave_sink *sink = impl_from_IMFFinalizableMediaSink(iface); + ULONG refcount = InterlockedDecrement(&sink->refcount); + + TRACE("%p, refcount %lu.\n", iface, refcount); + + if (!refcount) + { + if (sink->event_queue) + IMFMediaEventQueue_Release(sink->event_queue); + if (sink->stream_event_queue) + IMFMediaEventQueue_Release(sink->stream_event_queue); + IMFByteStream_Release(sink->bytestream); + DeleteCriticalSection(&sink->cs); + free(sink); + } + + return refcount; +} + +static HRESULT WINAPI wave_sink_GetCharacteristics(IMFFinalizableMediaSink *iface, DWORD *flags) +{ + struct wave_sink *sink = impl_from_IMFFinalizableMediaSink(iface); + + TRACE("%p, %p.\n", iface, flags); + + if (sink->flags & SINK_SHUT_DOWN) + return MF_E_SHUTDOWN; + + *flags = MEDIASINK_FIXED_STREAMS | MEDIASINK_RATELESS; + + return S_OK; +} + +static HRESULT WINAPI wave_sink_AddStreamSink(IMFFinalizableMediaSink *iface, DWORD stream_sink_id, + IMFMediaType *media_type, IMFStreamSink **stream_sink) +{ + struct wave_sink *sink = impl_from_IMFFinalizableMediaSink(iface); + + TRACE("%p, %#lx, %p, %p.\n", iface, stream_sink_id, media_type, stream_sink); + + return sink->flags & SINK_SHUT_DOWN ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED; +} + +static HRESULT WINAPI wave_sink_RemoveStreamSink(IMFFinalizableMediaSink *iface, DWORD stream_sink_id) +{ + struct wave_sink *sink = impl_from_IMFFinalizableMediaSink(iface); + + TRACE("%p, %#lx.\n", iface, stream_sink_id); + + return sink->flags & SINK_SHUT_DOWN ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED; +} + +static HRESULT WINAPI wave_sink_GetStreamSinkCount(IMFFinalizableMediaSink *iface, DWORD *count) +{ + struct wave_sink *sink = impl_from_IMFFinalizableMediaSink(iface); + + TRACE("%p, %p.\n", iface, count); + + if (!count) + return E_POINTER; + + if (sink->flags & SINK_SHUT_DOWN) + return MF_E_SHUTDOWN; + + *count = 1; + + return S_OK; +} + +static HRESULT WINAPI wave_sink_GetStreamSinkByIndex(IMFFinalizableMediaSink *iface, DWORD index, + IMFStreamSink **stream) +{ + struct wave_sink *sink = impl_from_IMFFinalizableMediaSink(iface); + HRESULT hr = S_OK; + + TRACE("%p, %lu, %p.\n", iface, index, stream); + + EnterCriticalSection(&sink->cs); + + if (sink->flags & SINK_SHUT_DOWN) + hr = MF_E_SHUTDOWN; + else if (index) + hr = MF_E_INVALIDINDEX; + else + { + *stream = &sink->IMFStreamSink_iface; + IMFStreamSink_AddRef(*stream); + } + + LeaveCriticalSection(&sink->cs); + + return hr; +} + +static HRESULT WINAPI wave_sink_GetStreamSinkById(IMFFinalizableMediaSink *iface, DWORD stream_sink_id, + IMFStreamSink **stream) +{ + struct wave_sink *sink = impl_from_IMFFinalizableMediaSink(iface); + HRESULT hr = S_OK; + + TRACE("%p, %#lx, %p.\n", iface, stream_sink_id, stream); + + EnterCriticalSection(&sink->cs); + + if (sink->flags & SINK_SHUT_DOWN) + hr = MF_E_SHUTDOWN; + else if (stream_sink_id != 1) + hr = MF_E_INVALIDSTREAMNUMBER; + else + { + *stream = &sink->IMFStreamSink_iface; + IMFStreamSink_AddRef(*stream); + } + + LeaveCriticalSection(&sink->cs); + + return hr; +} + +static HRESULT WINAPI wave_sink_SetPresentationClock(IMFFinalizableMediaSink *iface, IMFPresentationClock *clock) +{ + FIXME("%p, %p.\n", iface, clock); + + return E_NOTIMPL; +} + +static HRESULT WINAPI wave_sink_GetPresentationClock(IMFFinalizableMediaSink *iface, IMFPresentationClock **clock) +{ + FIXME("%p, %p.\n", iface, clock); + + return E_NOTIMPL; +} + +static HRESULT WINAPI wave_sink_Shutdown(IMFFinalizableMediaSink *iface) +{ + struct wave_sink *sink = impl_from_IMFFinalizableMediaSink(iface); + HRESULT hr = S_OK; + + TRACE("%p.\n", iface); + + EnterCriticalSection(&sink->cs); + + if (sink->flags & SINK_SHUT_DOWN) + hr = MF_E_SHUTDOWN; + else + { + sink->flags |= SINK_SHUT_DOWN; + IMFMediaEventQueue_Shutdown(sink->event_queue); + IMFMediaEventQueue_Shutdown(sink->stream_event_queue); + } + + LeaveCriticalSection(&sink->cs); + + return hr; +} + +static HRESULT WINAPI wave_sink_BeginFinalize(IMFFinalizableMediaSink *iface, IMFAsyncCallback *callback, IUnknown *state) +{ + FIXME("%p, %p, %p.\n", iface, callback, state); + + return E_NOTIMPL; +} + +static HRESULT WINAPI wave_sink_EndFinalize(IMFFinalizableMediaSink *iface, IMFAsyncResult *result) +{ + FIXME("%p, %p.\n", iface, result); + + return E_NOTIMPL; +} + +static const IMFFinalizableMediaSinkVtbl wave_sink_vtbl = +{ + wave_sink_QueryInterface, + wave_sink_AddRef, + wave_sink_Release, + wave_sink_GetCharacteristics, + wave_sink_AddStreamSink, + wave_sink_RemoveStreamSink, + wave_sink_GetStreamSinkCount, + wave_sink_GetStreamSinkByIndex, + wave_sink_GetStreamSinkById, + wave_sink_SetPresentationClock, + wave_sink_GetPresentationClock, + wave_sink_Shutdown, + wave_sink_BeginFinalize, + wave_sink_EndFinalize, +}; + +static HRESULT WINAPI wave_sink_events_QueryInterface(IMFMediaEventGenerator *iface, REFIID riid, void **obj) +{ + struct wave_sink *sink = impl_from_IMFMediaEventGenerator(iface); + return IMFFinalizableMediaSink_QueryInterface(&sink->IMFFinalizableMediaSink_iface, riid, obj); +} + +static ULONG WINAPI wave_sink_events_AddRef(IMFMediaEventGenerator *iface) +{ + struct wave_sink *sink = impl_from_IMFMediaEventGenerator(iface); + return IMFFinalizableMediaSink_AddRef(&sink->IMFFinalizableMediaSink_iface); +} + +static ULONG WINAPI wave_sink_events_Release(IMFMediaEventGenerator *iface) +{ + struct wave_sink *sink = impl_from_IMFMediaEventGenerator(iface); + return IMFFinalizableMediaSink_Release(&sink->IMFFinalizableMediaSink_iface); +} + +static HRESULT WINAPI wave_sink_events_GetEvent(IMFMediaEventGenerator *iface, DWORD flags, IMFMediaEvent **event) +{ + struct wave_sink *sink = impl_from_IMFMediaEventGenerator(iface); + + TRACE("%p, %#lx, %p.\n", iface, flags, event); + + return IMFMediaEventQueue_GetEvent(sink->event_queue, flags, event); +} + +static HRESULT WINAPI wave_sink_events_BeginGetEvent(IMFMediaEventGenerator *iface, IMFAsyncCallback *callback, + IUnknown *state) +{ + struct wave_sink *sink = impl_from_IMFMediaEventGenerator(iface); + + TRACE("%p, %p, %p.\n", iface, callback, state); + + return IMFMediaEventQueue_BeginGetEvent(sink->event_queue, callback, state); +} + +static HRESULT WINAPI wave_sink_events_EndGetEvent(IMFMediaEventGenerator *iface, IMFAsyncResult *result, + IMFMediaEvent **event) +{ + struct wave_sink *sink = impl_from_IMFMediaEventGenerator(iface); + + TRACE("%p, %p, %p.\n", iface, result, event); + + return IMFMediaEventQueue_EndGetEvent(sink->event_queue, result, event); +} + +static HRESULT WINAPI wave_sink_events_QueueEvent(IMFMediaEventGenerator *iface, MediaEventType event_type, + REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) +{ + struct wave_sink *sink = impl_from_IMFMediaEventGenerator(iface); + + TRACE("%p, %lu, %s, %#lx, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value); + + return IMFMediaEventQueue_QueueEventParamVar(sink->event_queue, event_type, ext_type, hr, value); +} + +static const IMFMediaEventGeneratorVtbl wave_sink_events_vtbl = +{ + wave_sink_events_QueryInterface, + wave_sink_events_AddRef, + wave_sink_events_Release, + wave_sink_events_GetEvent, + wave_sink_events_BeginGetEvent, + wave_sink_events_EndGetEvent, + wave_sink_events_QueueEvent, +}; + +static HRESULT WINAPI wave_stream_sink_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj) +{ + struct wave_sink *sink = impl_from_IMFStreamSink(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFStreamSink) || + IsEqualIID(riid, &IID_IMFMediaEventGenerator) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = &sink->IMFStreamSink_iface; + } + else + { + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*obj); + + return S_OK; +} + +static ULONG WINAPI wave_stream_sink_AddRef(IMFStreamSink *iface) +{ + struct wave_sink *sink = impl_from_IMFStreamSink(iface); + return IMFFinalizableMediaSink_AddRef(&sink->IMFFinalizableMediaSink_iface); +} + +static ULONG WINAPI wave_stream_sink_Release(IMFStreamSink *iface) +{ + struct wave_sink *sink = impl_from_IMFStreamSink(iface); + return IMFFinalizableMediaSink_Release(&sink->IMFFinalizableMediaSink_iface); +} + +static HRESULT WINAPI wave_stream_sink_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event) +{ + struct wave_sink *sink = impl_from_IMFStreamSink(iface); + + TRACE("%p, %#lx, %p.\n", iface, flags, event); + + if (sink->flags & SINK_SHUT_DOWN) + return MF_E_STREAMSINK_REMOVED; + + return IMFMediaEventQueue_GetEvent(sink->stream_event_queue, flags, event); +} + +static HRESULT WINAPI wave_stream_sink_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback, + IUnknown *state) +{ + struct wave_sink *sink = impl_from_IMFStreamSink(iface); + + TRACE("%p, %p, %p.\n", iface, callback, state); + + if (sink->flags & SINK_SHUT_DOWN) + return MF_E_STREAMSINK_REMOVED; + + return IMFMediaEventQueue_BeginGetEvent(sink->stream_event_queue, callback, state); +} + +static HRESULT WINAPI wave_stream_sink_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result, + IMFMediaEvent **event) +{ + struct wave_sink *sink = impl_from_IMFStreamSink(iface); + + TRACE("%p, %p, %p.\n", iface, result, event); + + if (sink->flags & SINK_SHUT_DOWN) + return MF_E_STREAMSINK_REMOVED; + + return IMFMediaEventQueue_EndGetEvent(sink->stream_event_queue, result, event); +} + +static HRESULT WINAPI wave_stream_sink_QueueEvent(IMFStreamSink *iface, MediaEventType event_type, + REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) +{ + struct wave_sink *sink = impl_from_IMFStreamSink(iface); + + TRACE("%p, %lu, %s, %#lx, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value); + + if (sink->flags & SINK_SHUT_DOWN) + return MF_E_STREAMSINK_REMOVED; + + return IMFMediaEventQueue_QueueEventParamVar(sink->stream_event_queue, event_type, ext_type, hr, value); +} + +static HRESULT WINAPI wave_stream_sink_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **ret) +{ + struct wave_sink *sink = impl_from_IMFStreamSink(iface); + + TRACE("%p, %p.\n", iface, ret); + + if (sink->flags & SINK_SHUT_DOWN) + return MF_E_STREAMSINK_REMOVED; + + *ret = (IMFMediaSink *)&sink->IMFFinalizableMediaSink_iface; + IMFMediaSink_AddRef(*ret); + + return S_OK; +} + +static HRESULT WINAPI wave_stream_sink_GetIdentifier(IMFStreamSink *iface, DWORD *identifier) +{ + struct wave_sink *sink = impl_from_IMFStreamSink(iface); + + TRACE("%p, %p.\n", iface, identifier); + + if (sink->flags & SINK_SHUT_DOWN) + return MF_E_STREAMSINK_REMOVED; + + *identifier = 1; + + return S_OK; +} + +static HRESULT WINAPI wave_stream_sink_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler) +{ + FIXME("%p, %p.\n", iface, handler); + + return E_NOTIMPL; +} + +static HRESULT WINAPI wave_stream_sink_ProcessSample(IMFStreamSink *iface, IMFSample *sample) +{ + FIXME("%p, %p.\n", iface, sample); + + return E_NOTIMPL; +} + +static HRESULT WINAPI wave_stream_sink_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type, + const PROPVARIANT *marker_value, const PROPVARIANT *context_value) +{ + FIXME("%p, %d, %p, %p.\n", iface, marker_type, marker_value, context_value); + + return E_NOTIMPL; +} + +static HRESULT WINAPI wave_stream_sink_Flush(IMFStreamSink *iface) +{ + FIXME("%p.\n", iface); + + return E_NOTIMPL; +} + +static const IMFStreamSinkVtbl wave_stream_sink_vtbl = +{ + wave_stream_sink_QueryInterface, + wave_stream_sink_AddRef, + wave_stream_sink_Release, + wave_stream_sink_GetEvent, + wave_stream_sink_BeginGetEvent, + wave_stream_sink_EndGetEvent, + wave_stream_sink_QueueEvent, + wave_stream_sink_GetMediaSink, + wave_stream_sink_GetIdentifier, + wave_stream_sink_GetMediaTypeHandler, + wave_stream_sink_ProcessSample, + wave_stream_sink_PlaceMarker, + wave_stream_sink_Flush, +}; + /*********************************************************************** - * MFCreateWAVEMediaSink (mfplat.@) + * MFCreateWAVEMediaSink (mfsrcsnk.@) */ HRESULT WINAPI MFCreateWAVEMediaSink(IMFByteStream *bytestream, IMFMediaType *media_type, IMFMediaSink **sink) { - FIXME("%p, %p, %p.\n", bytestream, media_type, sink); + struct wave_sink *object; + DWORD flags = 0; + HRESULT hr;
- return E_NOTIMPL; + TRACE("%p, %p, %p.\n", bytestream, media_type, sink); + + if (!bytestream || !media_type || !sink) + return E_POINTER; + + if (FAILED(hr = IMFByteStream_GetCapabilities(bytestream, &flags))) return hr; + if (!(flags & MFBYTESTREAM_IS_WRITABLE)) return E_INVALIDARG; + + /* FIXME: do basic media type validation */ + + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + object->IMFFinalizableMediaSink_iface.lpVtbl = &wave_sink_vtbl; + object->IMFMediaEventGenerator_iface.lpVtbl = &wave_sink_events_vtbl; + object->IMFStreamSink_iface.lpVtbl = &wave_stream_sink_vtbl; + object->refcount = 1; + IMFByteStream_AddRef((object->bytestream = bytestream)); + InitializeCriticalSection(&object->cs); + + if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) + goto failed; + + if (FAILED(hr = MFCreateEventQueue(&object->stream_event_queue))) + goto failed; + + *sink = (IMFMediaSink *)&object->IMFFinalizableMediaSink_iface; + + return S_OK; + +failed: + + IMFFinalizableMediaSink_Release(&object->IMFFinalizableMediaSink_iface); + + return hr; }