Signed-off-by: Nikolay Sivov nsivov@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,
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/samplegrabber.c | 98 ++++++++++++++++++++++++++++++++++++++++- dlls/mf/tests/mf.c | 37 +++++++--------- 2 files changed, 112 insertions(+), 23 deletions(-)
diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index 997c9db539..a6a18dd96f 100644 --- a/dlls/mf/samplegrabber.c +++ b/dlls/mf/samplegrabber.c @@ -30,6 +30,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); struct sample_grabber_stream { IMFStreamSink IMFStreamSink_iface; + IMFMediaTypeHandler IMFMediaTypeHandler_iface; LONG refcount; IMFMediaSink *sink; }; @@ -69,6 +70,11 @@ static struct sample_grabber_stream *impl_from_IMFStreamSink(IMFStreamSink *ifac return CONTAINING_RECORD(iface, struct sample_grabber_stream, IMFStreamSink_iface); }
+static struct sample_grabber_stream *impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler *iface) +{ + return CONTAINING_RECORD(iface, struct sample_grabber_stream, IMFMediaTypeHandler_iface); +} + static HRESULT WINAPI sample_grabber_stream_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj) { struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface); @@ -80,6 +86,10 @@ static HRESULT WINAPI sample_grabber_stream_QueryInterface(IMFStreamSink *iface, { *obj = &stream->IMFStreamSink_iface; } + else if (IsEqualIID(riid, &IID_IMFMediaTypeHandler)) + { + *obj = &stream->IMFMediaTypeHandler_iface; + } else { WARN("Unsupported %s.\n", debugstr_guid(riid)); @@ -172,9 +182,14 @@ static HRESULT WINAPI sample_grabber_stream_GetIdentifier(IMFStreamSink *iface,
static HRESULT WINAPI sample_grabber_stream_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler) { - FIXME("%p, %p.\n", iface, handler); + struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
- return E_NOTIMPL; + TRACE("%p, %p.\n", iface, handler); + + *handler = &stream->IMFMediaTypeHandler_iface; + IMFMediaTypeHandler_AddRef(*handler); + + return S_OK; }
static HRESULT WINAPI sample_grabber_stream_ProcessSample(IMFStreamSink *iface, IMFSample *sample) @@ -216,6 +231,84 @@ static const IMFStreamSinkVtbl sample_grabber_stream_vtbl = sample_grabber_stream_Flush, };
+static HRESULT WINAPI sample_grabber_stream_type_handler_QueryInterface(IMFMediaTypeHandler *iface, REFIID riid, + void **obj) +{ + struct sample_grabber_stream *stream = impl_from_IMFMediaTypeHandler(iface); + return IMFStreamSink_QueryInterface(&stream->IMFStreamSink_iface, riid, obj); +} + +static ULONG WINAPI sample_grabber_stream_type_handler_AddRef(IMFMediaTypeHandler *iface) +{ + struct sample_grabber_stream *stream = impl_from_IMFMediaTypeHandler(iface); + return IMFStreamSink_AddRef(&stream->IMFStreamSink_iface); +} + +static ULONG WINAPI sample_grabber_stream_type_handler_Release(IMFMediaTypeHandler *iface) +{ + struct sample_grabber_stream *stream = impl_from_IMFMediaTypeHandler(iface); + return IMFStreamSink_Release(&stream->IMFStreamSink_iface); +} + +static HRESULT WINAPI sample_grabber_stream_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler *iface, + IMFMediaType *in_type, IMFMediaType **out_type) +{ + FIXME("%p, %p, %p.\n", iface, in_type, out_type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_grabber_stream_type_handler_GetMediaTypeCount(IMFMediaTypeHandler *iface, DWORD *count) +{ + FIXME("%p, %p.\n", iface, count); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_grabber_stream_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler *iface, DWORD index, + IMFMediaType **type) +{ + FIXME("%p, %u, %p.\n", iface, index, type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_grabber_stream_type_handler_SetCurrentMediaType(IMFMediaTypeHandler *iface, + IMFMediaType *type) +{ + FIXME("%p, %p.\n", iface, type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_grabber_stream_type_handler_GetCurrentMediaType(IMFMediaTypeHandler *iface, + IMFMediaType **type) +{ + FIXME("%p, %p.\n", iface, type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_grabber_stream_type_handler_GetMajorType(IMFMediaTypeHandler *iface, GUID *type) +{ + FIXME("%p, %p.\n", iface, type); + + return E_NOTIMPL; +} + +static const IMFMediaTypeHandlerVtbl sample_grabber_stream_type_handler_vtbl = +{ + sample_grabber_stream_type_handler_QueryInterface, + sample_grabber_stream_type_handler_AddRef, + sample_grabber_stream_type_handler_Release, + sample_grabber_stream_type_handler_IsMediaTypeSupported, + sample_grabber_stream_type_handler_GetMediaTypeCount, + sample_grabber_stream_type_handler_GetMediaTypeByIndex, + sample_grabber_stream_type_handler_SetCurrentMediaType, + sample_grabber_stream_type_handler_GetCurrentMediaType, + sample_grabber_stream_type_handler_GetMajorType, +}; + static HRESULT WINAPI sample_grabber_sink_QueryInterface(IMFMediaSink *iface, REFIID riid, void **obj) { struct sample_grabber *grabber = impl_from_IMFMediaSink(iface); @@ -424,6 +517,7 @@ static HRESULT sample_grabber_create_stream(IMFMediaSink *sink, IMFStreamSink ** return E_OUTOFMEMORY;
object->IMFStreamSink_iface.lpVtbl = &sample_grabber_stream_vtbl; + object->IMFMediaTypeHandler_iface.lpVtbl = &sample_grabber_stream_type_handler_vtbl; object->refcount = 1; object->sink = sink; IMFMediaSink_AddRef(object->sink); diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index f2895d5bd3..ee5495444f 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -1724,22 +1724,19 @@ todo_wine 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); + hr = IMFStreamSink_GetMediaTypeHandler(stream, &handler); + ok(hr == S_OK, "Failed to get type handler, hr %#x.\n", hr); + hr = IMFMediaTypeHandler_GetMediaTypeCount(handler, &count); +todo_wine { + ok(hr == S_OK, "Failed to get media type count, hr %#x.\n", hr); + ok(count == 0, "Unexpected count %u.\n", count); +} + ok(handler == handler2, "Unexpected handler.\n");
- ok(handler == handler2, "Unexpected handler.\n"); - - IMFMediaTypeHandler_Release(handler); - IMFMediaTypeHandler_Release(handler2); - } + IMFMediaTypeHandler_Release(handler); + IMFMediaTypeHandler_Release(handler2);
hr = IMFActivate_ShutdownObject(activate); todo_wine @@ -1773,16 +1770,14 @@ todo_wine 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 = IMFMediaTypeHandler_GetMediaTypeCount(handler, &count); +todo_wine { + 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
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=52501
Your paranoid android.
=== wvistau64 (32 bit report) ===
mf: mf.c:1784: Test failed: Failed to flush, hr 0xc00d36b6.
=== wvistau64_zh_CN (32 bit report) ===
mf: mf.c:1784: Test failed: Failed to flush, hr 0xc00d36b6.
=== wvistau64_fr (32 bit report) ===
mf: mf.c:1784: Test failed: Failed to flush, hr 0xc00d36b6.
=== wvistau64_he (32 bit report) ===
mf: mf.c:1784: Test failed: Failed to flush, hr 0xc00d36b6.
=== w7u (32 bit report) ===
mf: mf.c:1784: Test failed: Failed to flush, hr 0xc00d36b6.
=== w7pro64 (32 bit report) ===
mf: mf.c:1784: Test failed: Failed to flush, hr 0xc00d36b6.
=== wvistau64 (64 bit report) ===
mf: mf.c:1784: Test failed: Failed to flush, hr 0xc00d36b6.
=== w7pro64 (64 bit report) ===
mf: mf.c:1784: Test failed: Failed to flush, hr 0xc00d36b6.
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/samplegrabber.c | 76 +++++++++++++++++++++++++++++++++++++++++ dlls/mf/tests/mf.c | 4 +-- 2 files changed, 77 insertions(+), 3 deletions(-)
diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index a6a18dd96f..f0b23241e0 100644 --- a/dlls/mf/samplegrabber.c +++ b/dlls/mf/samplegrabber.c @@ -38,6 +38,7 @@ struct sample_grabber_stream struct sample_grabber { IMFMediaSink IMFMediaSink_iface; + IMFClockStateSink IMFClockStateSink_iface; LONG refcount; IMFSampleGrabberSinkCallback *callback; IMFMediaType *media_type; @@ -65,6 +66,11 @@ static struct sample_grabber *impl_from_IMFMediaSink(IMFMediaSink *iface) return CONTAINING_RECORD(iface, struct sample_grabber, IMFMediaSink_iface); }
+static struct sample_grabber *impl_from_IMFClockStateSink(IMFClockStateSink *iface) +{ + return CONTAINING_RECORD(iface, struct sample_grabber, IMFClockStateSink_iface); +} + static struct sample_grabber_stream *impl_from_IMFStreamSink(IMFStreamSink *iface) { return CONTAINING_RECORD(iface, struct sample_grabber_stream, IMFStreamSink_iface); @@ -320,6 +326,10 @@ static HRESULT WINAPI sample_grabber_sink_QueryInterface(IMFMediaSink *iface, RE { *obj = &grabber->IMFMediaSink_iface; } + else if (IsEqualIID(riid, &IID_IMFClockStateSink)) + { + *obj = &grabber->IMFClockStateSink_iface; + } else { WARN("Unsupported %s.\n", debugstr_guid(riid)); @@ -508,6 +518,71 @@ static const IMFMediaSinkVtbl sample_grabber_sink_vtbl = sample_grabber_sink_Shutdown, };
+static HRESULT WINAPI sample_grabber_clock_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj) +{ + struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface); + return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj); +} + +static ULONG WINAPI sample_grabber_clock_sink_AddRef(IMFClockStateSink *iface) +{ + struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface); + return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface); +} + +static ULONG WINAPI sample_grabber_clock_sink_Release(IMFClockStateSink *iface) +{ + struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface); + return IMFMediaSink_Release(&grabber->IMFMediaSink_iface); +} + +static HRESULT WINAPI sample_grabber_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset) +{ + FIXME("%p, %s, %s.\n", iface, wine_dbgstr_longlong(systime), wine_dbgstr_longlong(offset)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_grabber_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime) +{ + FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(systime)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_grabber_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime) +{ + FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(systime)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_grabber_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime) +{ + FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(systime)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_grabber_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME systime, float rate) +{ + FIXME("%p, %s, %f.\n", iface, wine_dbgstr_longlong(systime), rate); + + return E_NOTIMPL; +} + +static const IMFClockStateSinkVtbl sample_grabber_clock_sink_vtbl = +{ + sample_grabber_clock_sink_QueryInterface, + sample_grabber_clock_sink_AddRef, + sample_grabber_clock_sink_Release, + sample_grabber_clock_sink_OnClockStart, + sample_grabber_clock_sink_OnClockStop, + sample_grabber_clock_sink_OnClockPause, + sample_grabber_clock_sink_OnClockRestart, + sample_grabber_clock_sink_OnClockSetRate, +}; + static HRESULT sample_grabber_create_stream(IMFMediaSink *sink, IMFStreamSink **stream) { struct sample_grabber_stream *object; @@ -540,6 +615,7 @@ static HRESULT sample_grabber_create_object(IMFAttributes *attributes, void *use return E_OUTOFMEMORY;
object->IMFMediaSink_iface.lpVtbl = &sample_grabber_sink_vtbl; + object->IMFClockStateSink_iface.lpVtbl = &sample_grabber_clock_sink_vtbl; object->refcount = 1; object->callback = context->callback; IMFSampleGrabberSinkCallback_AddRef(object->callback); diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index ee5495444f..299e250a22 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -1709,10 +1709,8 @@ static void test_sample_grabber(void) 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); + IMFClockStateSink_Release(clocksink);
hr = IMFMediaSink_QueryInterface(sink, &IID_IMFMediaEventGenerator, (void **)&eg); todo_wine
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=52502
Your paranoid android.
=== wvistau64 (32 bit report) ===
mf: mf.c:1782: Test failed: Failed to flush, hr 0xc00d36b6.
=== wvistau64_zh_CN (32 bit report) ===
mf: mf.c:1782: Test failed: Failed to flush, hr 0xc00d36b6.
=== wvistau64_fr (32 bit report) ===
mf: mf.c:1782: Test failed: Failed to flush, hr 0xc00d36b6.
=== wvistau64_he (32 bit report) ===
mf: mf.c:1782: Test failed: Failed to flush, hr 0xc00d36b6.
=== w7u (32 bit report) ===
mf: mf.c:1782: Test failed: Failed to flush, hr 0xc00d36b6.
=== w7pro64 (32 bit report) ===
mf: mf.c:1782: Test failed: Failed to flush, hr 0xc00d36b6.
=== wvistau64 (64 bit report) ===
mf: mf.c:1782: Test failed: Failed to flush, hr 0xc00d36b6.
=== w7pro64 (64 bit report) ===
mf: mf.c:1782: Test failed: Failed to flush, hr 0xc00d36b6.
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/samplegrabber.c | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-)
diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index f0b23241e0..a94b825ba8 100644 --- a/dlls/mf/samplegrabber.c +++ b/dlls/mf/samplegrabber.c @@ -18,6 +18,7 @@
#define COBJMACROS
+#include "mfapi.h" #include "mfidl.h" #include "mferror.h" #include "mf_private.h" @@ -33,6 +34,7 @@ struct sample_grabber_stream IMFMediaTypeHandler IMFMediaTypeHandler_iface; LONG refcount; IMFMediaSink *sink; + IMFMediaEventQueue *event_queue; };
struct sample_grabber @@ -128,6 +130,8 @@ static ULONG WINAPI sample_grabber_stream_Release(IMFStreamSink *iface) if (!refcount) { IMFMediaSink_Release(stream->sink); + IMFMediaEventQueue_Shutdown(stream->event_queue); + IMFMediaEventQueue_Release(stream->event_queue); heap_free(stream); }
@@ -136,33 +140,41 @@ static ULONG WINAPI sample_grabber_stream_Release(IMFStreamSink *iface)
static HRESULT WINAPI sample_grabber_stream_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event) { - FIXME("%p, %#x, %p.\n", iface, flags, event); + struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
- return E_NOTIMPL; + TRACE("%p, %#x, %p.\n", iface, flags, event); + + return IMFMediaEventQueue_GetEvent(stream->event_queue, flags, event); }
static HRESULT WINAPI sample_grabber_stream_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback, IUnknown *state) { - FIXME("%p, %p, %p.\n", iface, callback, state); + struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
- return E_NOTIMPL; + TRACE("%p, %p, %p.\n", iface, callback, state); + + return IMFMediaEventQueue_BeginGetEvent(stream->event_queue, callback, state); }
static HRESULT WINAPI sample_grabber_stream_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result, IMFMediaEvent **event) { - FIXME("%p, %p, %p.\n", iface, result, event); + struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
- return E_NOTIMPL; + TRACE("%p, %p, %p.\n", iface, result, event); + + return IMFMediaEventQueue_EndGetEvent(stream->event_queue, result, event); }
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); + struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
- return E_NOTIMPL; + TRACE("%p, %u, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value); + + return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, event_type, ext_type, hr, value); }
static HRESULT WINAPI sample_grabber_stream_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **sink) @@ -586,6 +598,7 @@ static const IMFClockStateSinkVtbl sample_grabber_clock_sink_vtbl = static HRESULT sample_grabber_create_stream(IMFMediaSink *sink, IMFStreamSink **stream) { struct sample_grabber_stream *object; + HRESULT hr;
object = heap_alloc_zero(sizeof(*object)); if (!object) @@ -597,9 +610,17 @@ static HRESULT sample_grabber_create_stream(IMFMediaSink *sink, IMFStreamSink ** object->sink = sink; IMFMediaSink_AddRef(object->sink);
+ if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) + goto failed; + *stream = &object->IMFStreamSink_iface;
return S_OK; + +failed: + IMFStreamSink_Release(&object->IMFStreamSink_iface); + + return hr; }
static HRESULT sample_grabber_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/samplegrabber.c | 107 +++++++++++++++++++++++++++++++++++++--- dlls/mf/tests/mf.c | 4 +- 2 files changed, 102 insertions(+), 9 deletions(-)
diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index a94b825ba8..b62502f4f1 100644 --- a/dlls/mf/samplegrabber.c +++ b/dlls/mf/samplegrabber.c @@ -41,11 +41,13 @@ struct sample_grabber { IMFMediaSink IMFMediaSink_iface; IMFClockStateSink IMFClockStateSink_iface; + IMFMediaEventGenerator IMFMediaEventGenerator_iface; LONG refcount; IMFSampleGrabberSinkCallback *callback; IMFMediaType *media_type; BOOL is_shut_down; IMFStreamSink *stream; + IMFMediaEventQueue *event_queue; CRITICAL_SECTION cs; };
@@ -73,6 +75,11 @@ static struct sample_grabber *impl_from_IMFClockStateSink(IMFClockStateSink *ifa return CONTAINING_RECORD(iface, struct sample_grabber, IMFClockStateSink_iface); }
+static struct sample_grabber *impl_from_IMFMediaEventGenerator(IMFMediaEventGenerator *iface) +{ + return CONTAINING_RECORD(iface, struct sample_grabber, IMFMediaEventGenerator_iface); +} + static struct sample_grabber_stream *impl_from_IMFStreamSink(IMFStreamSink *iface) { return CONTAINING_RECORD(iface, struct sample_grabber_stream, IMFStreamSink_iface); @@ -130,8 +137,11 @@ static ULONG WINAPI sample_grabber_stream_Release(IMFStreamSink *iface) if (!refcount) { IMFMediaSink_Release(stream->sink); - IMFMediaEventQueue_Shutdown(stream->event_queue); - IMFMediaEventQueue_Release(stream->event_queue); + if (stream->event_queue) + { + IMFMediaEventQueue_Shutdown(stream->event_queue); + IMFMediaEventQueue_Release(stream->event_queue); + } heap_free(stream); }
@@ -342,6 +352,10 @@ static HRESULT WINAPI sample_grabber_sink_QueryInterface(IMFMediaSink *iface, RE { *obj = &grabber->IMFClockStateSink_iface; } + else if (IsEqualIID(riid, &IID_IMFMediaEventGenerator)) + { + *obj = &grabber->IMFMediaEventGenerator_iface; + } else { WARN("Unsupported %s.\n", debugstr_guid(riid)); @@ -375,6 +389,11 @@ static ULONG WINAPI sample_grabber_sink_Release(IMFMediaSink *iface) { IMFSampleGrabberSinkCallback_Release(grabber->callback); IMFMediaType_Release(grabber->media_type); + if (grabber->event_queue) + { + IMFMediaEventQueue_Shutdown(grabber->event_queue); + IMFMediaEventQueue_Release(grabber->event_queue); + } DeleteCriticalSection(&grabber->cs); heap_free(grabber); } @@ -583,6 +602,74 @@ static HRESULT WINAPI sample_grabber_clock_sink_OnClockSetRate(IMFClockStateSink return E_NOTIMPL; }
+static HRESULT WINAPI sample_grabber_events_QueryInterface(IMFMediaEventGenerator *iface, REFIID riid, void **obj) +{ + struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface); + return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj); +} + +static ULONG WINAPI sample_grabber_events_AddRef(IMFMediaEventGenerator *iface) +{ + struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface); + return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface); +} + +static ULONG WINAPI sample_grabber_events_Release(IMFMediaEventGenerator *iface) +{ + struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface); + return IMFMediaSink_Release(&grabber->IMFMediaSink_iface); +} + +static HRESULT WINAPI sample_grabber_events_GetEvent(IMFMediaEventGenerator *iface, DWORD flags, IMFMediaEvent **event) +{ + struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface); + + TRACE("%p, %#x, %p.\n", iface, flags, event); + + return IMFMediaEventQueue_GetEvent(grabber->event_queue, flags, event); +} + +static HRESULT WINAPI sample_grabber_events_BeginGetEvent(IMFMediaEventGenerator *iface, IMFAsyncCallback *callback, + IUnknown *state) +{ + struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface); + + TRACE("%p, %p, %p.\n", iface, callback, state); + + return IMFMediaEventQueue_BeginGetEvent(grabber->event_queue, callback, state); +} + +static HRESULT WINAPI sample_grabber_events_EndGetEvent(IMFMediaEventGenerator *iface, IMFAsyncResult *result, + IMFMediaEvent **event) +{ + struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface); + + TRACE("%p, %p, %p.\n", iface, result, event); + + return IMFMediaEventQueue_EndGetEvent(grabber->event_queue, result, event); +} + +static HRESULT WINAPI sample_grabber_events_QueueEvent(IMFMediaEventGenerator *iface, MediaEventType event_type, + REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) +{ + struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface); + + TRACE("%p, %u, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value); + + return IMFMediaEventQueue_QueueEventParamVar(grabber->event_queue, event_type, ext_type, hr, value); +} + +static const IMFMediaEventGeneratorVtbl sample_grabber_sink_events_vtbl = +{ + sample_grabber_events_QueryInterface, + sample_grabber_events_AddRef, + sample_grabber_events_Release, + sample_grabber_events_GetEvent, + sample_grabber_events_BeginGetEvent, + sample_grabber_events_EndGetEvent, + sample_grabber_events_QueueEvent, +}; + static const IMFClockStateSinkVtbl sample_grabber_clock_sink_vtbl = { sample_grabber_clock_sink_QueryInterface, @@ -637,23 +724,31 @@ static HRESULT sample_grabber_create_object(IMFAttributes *attributes, void *use
object->IMFMediaSink_iface.lpVtbl = &sample_grabber_sink_vtbl; object->IMFClockStateSink_iface.lpVtbl = &sample_grabber_clock_sink_vtbl; + object->IMFMediaEventGenerator_iface.lpVtbl = &sample_grabber_sink_events_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; - } + goto failed; + + if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) + goto failed;
*obj = (IUnknown *)&object->IMFMediaSink_iface;
TRACE("Created %p.\n", *obj);
return S_OK; + +failed: + + IMFMediaSink_Release(&object->IMFMediaSink_iface); + + return hr; }
static const struct activate_funcs sample_grabber_activate_funcs = diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 299e250a22..8f20104e06 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -1713,10 +1713,8 @@ static void test_sample_grabber(void) 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); + IMFMediaEventGenerator_Release(eg);
hr = IMFMediaSink_QueryInterface(sink, &IID_IMFPresentationTimeSource, (void **)&unk); ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=52504
Your paranoid android.
=== wvistau64 (32 bit report) ===
mf: mf.c:1780: Test failed: Failed to flush, hr 0xc00d36b6.
=== wvistau64_zh_CN (32 bit report) ===
mf: mf.c:1780: Test failed: Failed to flush, hr 0xc00d36b6.
=== wvistau64_fr (32 bit report) ===
mf: mf.c:1780: Test failed: Failed to flush, hr 0xc00d36b6.
=== wvistau64_he (32 bit report) ===
mf: mf.c:1780: Test failed: Failed to flush, hr 0xc00d36b6.
=== w7u (32 bit report) ===
mf: mf.c:1780: Test failed: Failed to flush, hr 0xc00d36b6.
=== w7pro64 (32 bit report) ===
mf: mf.c:1780: Test failed: Failed to flush, hr 0xc00d36b6.
=== wvistau64 (64 bit report) ===
mf: mf.c:1780: Test failed: Failed to flush, hr 0xc00d36b6.
=== w7pro64 (64 bit report) ===
mf: mf.c:1780: Test failed: Failed to flush, hr 0xc00d36b6.
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=52500
Your paranoid android.
=== wvistau64 (32 bit report) ===
mf: mf.c:1789: Test failed: Failed to flush, hr 0xc00d36b6.
=== wvistau64_zh_CN (32 bit report) ===
mf: mf.c:1789: Test failed: Failed to flush, hr 0xc00d36b6.
=== wvistau64_fr (32 bit report) ===
mf: mf.c:1789: Test failed: Failed to flush, hr 0xc00d36b6.
=== wvistau64_he (32 bit report) ===
mf: mf.c:1789: Test failed: Failed to flush, hr 0xc00d36b6.
=== w7u (32 bit report) ===
mf: mf.c:1789: Test failed: Failed to flush, hr 0xc00d36b6.
=== w7pro64 (32 bit report) ===
mf: mf.c:1789: Test failed: Failed to flush, hr 0xc00d36b6.
=== wvistau64 (64 bit report) ===
mf: mf.c:1789: Test failed: Failed to flush, hr 0xc00d36b6.
=== w7pro64 (64 bit report) ===
mf: mf.c:1789: Test failed: Failed to flush, hr 0xc00d36b6.