Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mf/main.c | 2 +-
dlls/mf/samplegrabber.c | 422 +++++++++++++++++++++++++++++++++++++++-
dlls/mf/tests/mf.c | 143 +++++++++++++-
include/mferror.h | 14 ++
include/mfidl.idl | 32 +++
5 files changed, 606 insertions(+), 7 deletions(-)
diff --git a/dlls/mf/main.c b/dlls/mf/main.c
index b5b4b0e7c8..6db13f19db 100644
--- a/dlls/mf/main.c
+++ b/dlls/mf/main.c
@@ -395,7 +395,7 @@ static HRESULT WINAPI activate_object_ActivateObject(IMFActivate *iface, REFIID
if (FAILED(hr = activate->funcs->create_object((IMFAttributes *)iface, activate->context, &object)))
return hr;
- if (!InterlockedCompareExchangePointer((void **)&activate->object, object, NULL))
+ if (InterlockedCompareExchangePointer((void **)&activate->object, object, NULL))
IUnknown_Release(object);
}
diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c
index 7b3536467c..997c9db539 100644
--- a/dlls/mf/samplegrabber.c
+++ b/dlls/mf/samplegrabber.c
@@ -19,6 +19,7 @@
#define COBJMACROS
#include "mfidl.h"
+#include "mferror.h"
#include "mf_private.h"
#include "wine/debug.h"
@@ -26,6 +27,24 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+struct sample_grabber_stream
+{
+ IMFStreamSink IMFStreamSink_iface;
+ LONG refcount;
+ IMFMediaSink *sink;
+};
+
+struct sample_grabber
+{
+ IMFMediaSink IMFMediaSink_iface;
+ LONG refcount;
+ IMFSampleGrabberSinkCallback *callback;
+ IMFMediaType *media_type;
+ BOOL is_shut_down;
+ IMFStreamSink *stream;
+ CRITICAL_SECTION cs;
+};
+
struct sample_grabber_activate_context
{
IMFMediaType *media_type;
@@ -40,13 +59,412 @@ static void sample_grabber_free_private(void *user_context)
heap_free(context);
}
-static HRESULT sample_grabber_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj)
+static struct sample_grabber *impl_from_IMFMediaSink(IMFMediaSink *iface)
+{
+ return CONTAINING_RECORD(iface, struct sample_grabber, IMFMediaSink_iface);
+}
+
+static struct sample_grabber_stream *impl_from_IMFStreamSink(IMFStreamSink *iface)
{
- FIXME("%p, %p, %p.\n", attributes, user_context, obj);
+ return CONTAINING_RECORD(iface, struct sample_grabber_stream, IMFStreamSink_iface);
+}
+
+static HRESULT WINAPI sample_grabber_stream_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj)
+{
+ struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+ if (IsEqualIID(riid, &IID_IMFStreamSink) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = &stream->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 sample_grabber_stream_AddRef(IMFStreamSink *iface)
+{
+ struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
+ ULONG refcount = InterlockedIncrement(&stream->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI sample_grabber_stream_Release(IMFStreamSink *iface)
+{
+ struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
+ ULONG refcount = InterlockedDecrement(&stream->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ IMFMediaSink_Release(stream->sink);
+ heap_free(stream);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI sample_grabber_stream_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event)
+{
+ FIXME("%p, %#x, %p.\n", iface, flags, event);
return E_NOTIMPL;
}
+static HRESULT WINAPI sample_grabber_stream_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback,
+ IUnknown *state)
+{
+ FIXME("%p, %p, %p.\n", iface, callback, state);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_stream_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result,
+ IMFMediaEvent **event)
+{
+ FIXME("%p, %p, %p.\n", iface, result, event);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_stream_QueueEvent(IMFStreamSink *iface, MediaEventType event_type,
+ REFGUID ext_type, HRESULT hr, const PROPVARIANT *value)
+{
+ FIXME("%p, %u, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_stream_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **sink)
+{
+ struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
+
+ TRACE("%p, %p.\n", iface, sink);
+
+ *sink = stream->sink;
+ IMFMediaSink_AddRef(*sink);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI sample_grabber_stream_GetIdentifier(IMFStreamSink *iface, DWORD *identifier)
+{
+ TRACE("%p, %p.\n", iface, identifier);
+
+ *identifier = 0;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI sample_grabber_stream_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler)
+{
+ FIXME("%p, %p.\n", iface, handler);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_stream_ProcessSample(IMFStreamSink *iface, IMFSample *sample)
+{
+ FIXME("%p, %p.\n", iface, sample);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_stream_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 sample_grabber_stream_Flush(IMFStreamSink *iface)
+{
+ FIXME("%p.\n", iface);
+
+ return E_NOTIMPL;
+}
+
+static const IMFStreamSinkVtbl sample_grabber_stream_vtbl =
+{
+ sample_grabber_stream_QueryInterface,
+ sample_grabber_stream_AddRef,
+ sample_grabber_stream_Release,
+ sample_grabber_stream_GetEvent,
+ sample_grabber_stream_BeginGetEvent,
+ sample_grabber_stream_EndGetEvent,
+ sample_grabber_stream_QueueEvent,
+ sample_grabber_stream_GetMediaSink,
+ sample_grabber_stream_GetIdentifier,
+ sample_grabber_stream_GetMediaTypeHandler,
+ sample_grabber_stream_ProcessSample,
+ sample_grabber_stream_PlaceMarker,
+ sample_grabber_stream_Flush,
+};
+
+static HRESULT WINAPI sample_grabber_sink_QueryInterface(IMFMediaSink *iface, REFIID riid, void **obj)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+ if (IsEqualIID(riid, &IID_IMFMediaSink) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = &grabber->IMFMediaSink_iface;
+ }
+ else
+ {
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown *)*obj);
+
+ return S_OK;
+}
+
+static ULONG WINAPI sample_grabber_sink_AddRef(IMFMediaSink *iface)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+ ULONG refcount = InterlockedIncrement(&grabber->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI sample_grabber_sink_Release(IMFMediaSink *iface)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+ ULONG refcount = InterlockedDecrement(&grabber->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ IMFSampleGrabberSinkCallback_Release(grabber->callback);
+ IMFMediaType_Release(grabber->media_type);
+ DeleteCriticalSection(&grabber->cs);
+ heap_free(grabber);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI sample_grabber_sink_GetCharacteristics(IMFMediaSink *iface, DWORD *flags)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+
+ TRACE("%p, %p.\n", iface, flags);
+
+ if (grabber->is_shut_down)
+ return MF_E_SHUTDOWN;
+
+ *flags = MEDIASINK_FIXED_STREAMS;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI sample_grabber_sink_AddStreamSink(IMFMediaSink *iface, DWORD stream_sink_id,
+ IMFMediaType *media_type, IMFStreamSink **stream_sink)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+
+ TRACE("%p, %#x, %p, %p.\n", iface, stream_sink_id, media_type, stream_sink);
+
+ return grabber->is_shut_down ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
+}
+
+static HRESULT WINAPI sample_grabber_sink_RemoveStreamSink(IMFMediaSink *iface, DWORD stream_sink_id)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+
+ TRACE("%p, %#x.\n", iface, stream_sink_id);
+
+ return grabber->is_shut_down ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
+}
+
+static HRESULT WINAPI sample_grabber_sink_GetStreamSinkCount(IMFMediaSink *iface, DWORD *count)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+
+ TRACE("%p, %p.\n", iface, count);
+
+ if (grabber->is_shut_down)
+ return MF_E_SHUTDOWN;
+
+ *count = 1;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI sample_grabber_sink_GetStreamSinkByIndex(IMFMediaSink *iface, DWORD index,
+ IMFStreamSink **stream)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %u, %p.\n", iface, index, stream);
+
+ if (grabber->is_shut_down)
+ return MF_E_SHUTDOWN;
+
+ EnterCriticalSection(&grabber->cs);
+
+ if (grabber->is_shut_down)
+ hr = MF_E_SHUTDOWN;
+ else if (index > 0)
+ hr = MF_E_INVALIDINDEX;
+ else
+ {
+ *stream = grabber->stream;
+ IMFStreamSink_AddRef(*stream);
+ }
+
+ LeaveCriticalSection(&grabber->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI sample_grabber_sink_GetStreamSinkById(IMFMediaSink *iface, DWORD stream_sink_id,
+ IMFStreamSink **stream)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %#x, %p.\n", iface, stream_sink_id, stream);
+
+ EnterCriticalSection(&grabber->cs);
+
+ if (grabber->is_shut_down)
+ hr = MF_E_SHUTDOWN;
+ else if (stream_sink_id > 0)
+ hr = MF_E_INVALIDSTREAMNUMBER;
+ else
+ {
+ *stream = grabber->stream;
+ IMFStreamSink_AddRef(*stream);
+ }
+
+ LeaveCriticalSection(&grabber->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI sample_grabber_sink_SetPresentationClock(IMFMediaSink *iface, IMFPresentationClock *clock)
+{
+ FIXME("%p, %p.\n", iface, clock);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_sink_GetPresentationClock(IMFMediaSink *iface, IMFPresentationClock **clock)
+{
+ FIXME("%p, %p.\n", iface, clock);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_sink_Shutdown(IMFMediaSink *iface)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+
+ TRACE("%p.\n", iface);
+
+ if (grabber->is_shut_down)
+ return MF_E_SHUTDOWN;
+
+ EnterCriticalSection(&grabber->cs);
+ grabber->is_shut_down = TRUE;
+ IMFStreamSink_Release(grabber->stream);
+ grabber->stream = NULL;
+ EnterCriticalSection(&grabber->cs);
+
+ return E_NOTIMPL;
+}
+
+static const IMFMediaSinkVtbl sample_grabber_sink_vtbl =
+{
+ sample_grabber_sink_QueryInterface,
+ sample_grabber_sink_AddRef,
+ sample_grabber_sink_Release,
+ sample_grabber_sink_GetCharacteristics,
+ sample_grabber_sink_AddStreamSink,
+ sample_grabber_sink_RemoveStreamSink,
+ sample_grabber_sink_GetStreamSinkCount,
+ sample_grabber_sink_GetStreamSinkByIndex,
+ sample_grabber_sink_GetStreamSinkById,
+ sample_grabber_sink_SetPresentationClock,
+ sample_grabber_sink_GetPresentationClock,
+ sample_grabber_sink_Shutdown,
+};
+
+static HRESULT sample_grabber_create_stream(IMFMediaSink *sink, IMFStreamSink **stream)
+{
+ struct sample_grabber_stream *object;
+
+ object = heap_alloc_zero(sizeof(*object));
+ if (!object)
+ return E_OUTOFMEMORY;
+
+ object->IMFStreamSink_iface.lpVtbl = &sample_grabber_stream_vtbl;
+ object->refcount = 1;
+ object->sink = sink;
+ IMFMediaSink_AddRef(object->sink);
+
+ *stream = &object->IMFStreamSink_iface;
+
+ return S_OK;
+}
+
+static HRESULT sample_grabber_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj)
+{
+ struct sample_grabber_activate_context *context = user_context;
+ struct sample_grabber *object;
+ HRESULT hr;
+
+ TRACE("%p, %p, %p.\n", attributes, user_context, obj);
+
+ object = heap_alloc_zero(sizeof(*object));
+ if (!object)
+ return E_OUTOFMEMORY;
+
+ object->IMFMediaSink_iface.lpVtbl = &sample_grabber_sink_vtbl;
+ object->refcount = 1;
+ object->callback = context->callback;
+ IMFSampleGrabberSinkCallback_AddRef(object->callback);
+ object->media_type = context->media_type;
+ IMFMediaType_AddRef(object->media_type);
+ InitializeCriticalSection(&object->cs);
+ if (FAILED(hr = sample_grabber_create_stream(&object->IMFMediaSink_iface, &object->stream)))
+ {
+ IMFMediaSink_Release(&object->IMFMediaSink_iface);
+ return hr;
+ }
+
+ *obj = (IUnknown *)&object->IMFMediaSink_iface;
+
+ TRACE("Created %p.\n", *obj);
+
+ return S_OK;
+}
+
static const struct activate_funcs sample_grabber_activate_funcs =
{
sample_grabber_create_object,
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index 37bcb8d029..f2895d5bd3 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -1230,7 +1230,6 @@ todo_wine
ok(hr == MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
hr = IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&sink);
-todo_wine
ok(hr == S_OK, "Failed to activate, hr %#x.\n", hr);
hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)sink);
@@ -1639,9 +1638,16 @@ static IMFSampleGrabberSinkCallback grabber_callback = { &grabber_callback_vtbl
static void test_sample_grabber(void)
{
+ IMFMediaTypeHandler *handler, *handler2;
+ IMFStreamSink *stream, *stream2;
+ IMFClockStateSink *clocksink;
+ IMFMediaEventGenerator *eg;
+ IMFMediaSink *sink, *sink2;
IMFMediaType *media_type;
+ DWORD flags, count, id;
IMFActivate *activate;
ULONG refcount;
+ IUnknown *unk;
HRESULT hr;
hr = MFCreateMediaType(&media_type);
@@ -1656,10 +1662,139 @@ static void test_sample_grabber(void)
hr = MFCreateSampleGrabberSinkActivate(media_type, &grabber_callback, &activate);
ok(hr == S_OK, "Failed to create grabber activate, hr %#x.\n", hr);
- refcount = IMFMediaType_Release(media_type);
- ok(refcount == 1, "Unexpected refcount %u.\n", refcount);
+ hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
+ hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
+
+ hr = IMFActivate_ActivateObject(activate, &IID_IMFMediaSink, (void **)&sink);
+ ok(hr == S_OK, "Failed to activate object, hr %#x.\n", hr);
+
+ hr = IMFMediaSink_GetCharacteristics(sink, &flags);
+ ok(hr == S_OK, "Failed to get sink flags, hr %#x.\n", hr);
+ ok(flags & MEDIASINK_FIXED_STREAMS, "Unexpected flags %#x.\n", flags);
+
+ hr = IMFMediaSink_GetStreamSinkCount(sink, &count);
+ ok(hr == S_OK, "Failed to get stream count, hr %#x.\n", hr);
+ ok(count == 1, "Unexpected stream count %u.\n", count);
+
+ EXPECT_REF(sink, 3);
+ hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream);
+ ok(hr == S_OK, "Failed to get sink stream, hr %#x.\n", hr);
+ EXPECT_REF(sink, 3);
+ EXPECT_REF(stream, 2);
+
+ hr = IMFStreamSink_GetIdentifier(stream, &id);
+ ok(hr == S_OK, "Failed to get stream id, hr %#x.\n", hr);
+ ok(id == 0, "Unexpected id %#x.\n", id);
+
+ hr = IMFStreamSink_GetMediaSink(stream, &sink2);
+ ok(hr == S_OK, "Failed to get media sink, hr %x.\n", hr);
+ ok(sink2 == sink, "Unexpected sink.\n");
+ IMFMediaSink_Release(sink2);
+
+ hr = IMFMediaSink_GetStreamSinkByIndex(sink, 1, &stream2);
+ ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_GetStreamSinkById(sink, 1, &stream2);
+ ok(hr == MF_E_INVALIDSTREAMNUMBER, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_AddStreamSink(sink, 1, NULL, &stream2);
+ ok(hr == MF_E_STREAMSINKS_FIXED, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_RemoveStreamSink(sink, 0);
+ ok(hr == MF_E_STREAMSINKS_FIXED, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_RemoveStreamSink(sink, 1);
+ ok(hr == MF_E_STREAMSINKS_FIXED, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_QueryInterface(sink, &IID_IMFClockStateSink, (void **)&clocksink);
+todo_wine
+ ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr);
+ if (SUCCEEDED(hr))
+ IMFClockStateSink_Release(clocksink);
+
+ hr = IMFMediaSink_QueryInterface(sink, &IID_IMFMediaEventGenerator, (void **)&eg);
+todo_wine
+ ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr);
+ if (SUCCEEDED(hr))
+ IMFMediaEventGenerator_Release(eg);
+
+ hr = IMFMediaSink_QueryInterface(sink, &IID_IMFPresentationTimeSource, (void **)&unk);
+ ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFStreamSink_QueryInterface(stream, &IID_IMFMediaTypeHandler, (void **)&handler2);
+todo_wine
+ ok(hr == S_OK, "Failed to get handler interface, hr %#x.\n", hr);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = IMFStreamSink_GetMediaTypeHandler(stream, &handler);
+ ok(hr == S_OK, "Failed to get type handler, hr %#x.\n", hr);
+ hr = IMFMediaTypeHandler_GetMediaTypeCount(handler, &count);
+ ok(hr == S_OK, "Failed to get media type count, hr %#x.\n", hr);
+ ok(count == 0, "Unexpected count %u.\n", count);
- IMFActivate_Release(activate);
+ ok(handler == handler2, "Unexpected handler.\n");
+
+ IMFMediaTypeHandler_Release(handler);
+ IMFMediaTypeHandler_Release(handler2);
+ }
+
+ hr = IMFActivate_ShutdownObject(activate);
+todo_wine
+ ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
+
+ hr = IMFMediaSink_Shutdown(sink);
+ ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_Shutdown(sink);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_GetCharacteristics(sink, &flags);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_AddStreamSink(sink, 1, NULL, &stream2);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_GetStreamSinkCount(sink, &count);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream2);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFStreamSink_GetMediaSink(stream, &sink2);
+ ok(hr == S_OK, "Failed to get media sink, hr %x.\n", hr);
+ ok(sink2 == sink, "Unexpected sink.\n");
+ IMFMediaSink_Release(sink2);
+
+ hr = IMFStreamSink_GetIdentifier(stream, &id);
+ ok(hr == S_OK, "Failed to get stream id, hr %#x.\n", hr);
+ ok(id == 0, "Unexpected id %#x.\n", id);
+
+ hr = IMFStreamSink_GetMediaTypeHandler(stream, &handler);
+todo_wine
+ ok(hr == S_OK, "Failed to get type handler, hr %#x.\n", hr);
+ if (SUCCEEDED(hr))
+ {
+ hr = IMFMediaTypeHandler_GetMediaTypeCount(handler, &count);
+ ok(hr == S_OK, "Failed to get media type count, hr %#x.\n", hr);
+ ok(count == 0, "Unexpected count %u.\n", count);
+
+ IMFMediaTypeHandler_Release(handler);
+ }
+
+ hr = IMFStreamSink_Flush(stream);
+todo_wine
+ ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
+
+ IMFMediaSink_Release(sink);
+ IMFStreamSink_Release(stream);
+
+ refcount = IMFActivate_Release(activate);
+ ok(!refcount, "Unexpected refcount %u.\n", refcount);
+
+ IMFMediaType_Release(media_type);
}
START_TEST(mf)
diff --git a/include/mferror.h b/include/mferror.h
index a0acf90f8b..4d3a530734 100644
--- a/include/mferror.h
+++ b/include/mferror.h
@@ -94,6 +94,20 @@
#define MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED _HRESULT_TYPEDEF_(0xc00d3e9c)
#define MF_E_UNSUPPORTED_CHARACTERISTICS _HRESULT_TYPEDEF_(0xc00d3e9e)
+#define MF_E_STREAMSINK_REMOVED _HRESULT_TYPEDEF_(0xc00d4a38)
+#define MF_E_STREAMSINKS_OUT_OF_SYNC _HRESULT_TYPEDEF_(0xc00d4a3a)
+#define MF_E_STREAMSINKS_FIXED _HRESULT_TYPEDEF_(0xc00d4a3b)
+#define MF_E_STREAMSINK_EXISTS _HRESULT_TYPEDEF_(0xc00d4a3c)
+#define MF_E_SAMPLEALLOCATOR_CANCELED _HRESULT_TYPEDEF_(0xc00d4a3d)
+#define MF_E_SAMPLEALLOCATOR_EMPTY _HRESULT_TYPEDEF_(0xc00d4a3e)
+#define MF_E_SINK_ALREADYSTOPPED _HRESULT_TYPEDEF_(0xc00d4a3f)
+#define MF_E_ASF_FILESINK_BITRATE_UNKNOWN _HRESULT_TYPEDEF_(0xc00d4a40)
+#define MF_E_SINK_NO_STREAMS _HRESULT_TYPEDEF_(0xc00d4a41)
+#define MF_S_SINK_NOT_FINALIZED _HRESULT_TYPEDEF_(0x000d4a42)
+#define MF_E_METADATA_TOO_LONG _HRESULT_TYPEDEF_(0xc00d4a43)
+#define MF_E_SINK_NO_SAMPLES_PROCESSED _HRESULT_TYPEDEF_(0xc00d4a44)
+#define MF_E_SINK_HEADERS_NOT_FOUND _HRESULT_TYPEDEF_(0xc00d4a45)
+
#define MF_E_TOPO_INVALID_OPTIONAL_NODE _HRESULT_TYPEDEF_(0xc00d520e)
#define MF_E_TOPO_CANNOT_FIND_DECRYPTOR _HRESULT_TYPEDEF_(0xc00d5211)
#define MF_E_TOPO_CODEC_NOT_FOUND _HRESULT_TYPEDEF_(0xc00d5212)
diff --git a/include/mfidl.idl b/include/mfidl.idl
index c024e67378..a5882e98e5 100644
--- a/include/mfidl.idl
+++ b/include/mfidl.idl
@@ -83,6 +83,14 @@ typedef enum _MF_TOPOLOGY_RESOLUTION_STATUS_FLAGS
MF_OPTIONAL_NODE_REJECTED_PROTECTED_PROCESS = 0x00000002,
} MF_TOPOLOGY_RESOLUTION_STATUS_FLAGS;
+typedef enum _MFSTREAMSINK_MARKER_TYPE
+{
+ MFSTREAMSINK_MARKER_DEFAULT,
+ MFSTREAMSINK_MARKER_ENDOFSEGMENT,
+ MFSTREAMSINK_MARKER_TICK,
+ MFSTREAMSINK_MARKER_EVENT,
+} MFSTREAMSINK_MARKER_TYPE;
+
[
object,
uuid(2eb1e945-18b8-4139-9b1a-d5d584818530),
@@ -646,6 +654,13 @@ interface IMFPresentationClock : IMFClock
HRESULT Pause();
}
+cpp_quote("#define MEDIASINK_FIXED_STREAMS 0x00000001")
+cpp_quote("#define MEDIASINK_CANNOT_MATCH_CLOCK 0x00000002")
+cpp_quote("#define MEDIASINK_RATELESS 0x00000004")
+cpp_quote("#define MEDIASINK_CLOCK_REQUIRED 0x00000008")
+cpp_quote("#define MEDIASINK_CAN_PREROLL 0x00000010")
+cpp_quote("#define MEDIASINK_REQUIRE_REFERENCE_MEDIATYPE 0x00000020")
+
[
object,
uuid(6ef2a660-47c0-4666-b13d-cbb717f2fa2c)
@@ -666,6 +681,23 @@ interface IMFMediaSink : IUnknown
HRESULT Shutdown();
}
+[
+ object,
+ uuid(0a97b3cf-8e7c-4a3d-8f8c-0c843dc247fb),
+]
+interface IMFStreamSink : IMFMediaEventGenerator
+{
+ HRESULT GetMediaSink([out] IMFMediaSink **sink);
+ HRESULT GetIdentifier([out] DWORD *identifier);
+ HRESULT GetMediaTypeHandler([out] IMFMediaTypeHandler **handler);
+ HRESULT ProcessSample([in] IMFSample *sample);
+ HRESULT PlaceMarker(
+ [in] MFSTREAMSINK_MARKER_TYPE marker_type,
+ [in] const PROPVARIANT *marker_value,
+ [in] const PROPVARIANT *context_value);
+ HRESULT Flush();
+}
+
typedef enum _MFSHUTDOWN_STATUS
{
MFSHUTDOWN_INITIATED,
--
2.20.1