-- v2: mf: Handle errors with source event generator in session. mf/test: Test error case when session is streaming.
From: Santino Mazza smazza@codeweavers.com
--- dlls/mf/tests/mf.c | 146 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 115 insertions(+), 31 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index aefc1b92b4d..1e46897bac8 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -48,18 +48,12 @@ #define SET_EXPECT(func) \ expect_ ## func = TRUE
-#define CHECK_EXPECT2(func) \ +#define CHECK_EXPECT(func) \ do { \ ok(expect_ ##func, "unexpected call " #func "\n"); \ called_ ## func = TRUE; \ }while(0)
-#define CHECK_EXPECT(func) \ - do { \ - CHECK_EXPECT2(func); \ - expect_ ## func = FALSE; \ - }while(0) - #define CHECK_CALLED(func) \ do { \ ok(called_ ## func, "expected " #func "\n"); \ @@ -272,6 +266,7 @@ static void init_sink_node(IMFStreamSink *stream_sink, MF_CONNECT_METHOD method, }
DEFINE_EXPECT(test_source_BeginGetEvent); +DEFINE_EXPECT(test_source_EndGetEvent); DEFINE_EXPECT(test_source_QueueEvent); DEFINE_EXPECT(test_source_Start);
@@ -279,7 +274,9 @@ struct test_source { IMFMediaSource IMFMediaSource_iface; LONG refcount; - HRESULT begin_get_event_res; + IMFMediaEventQueue *queue; + HRESULT begin_get_event_hr, end_get_event_hr, + start_hr, queue_event_hr; IMFPresentationDescriptor *pd; };
@@ -319,6 +316,8 @@ static ULONG WINAPI test_source_Release(IMFMediaSource *iface)
if (!refcount) { + IMFMediaEventQueue_Shutdown(source->queue); + IMFMediaEventQueue_Release(source->queue); IMFPresentationDescriptor_Release(source->pd); free(source); } @@ -336,20 +335,33 @@ static HRESULT WINAPI test_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncC { struct test_source *source = impl_from_IMFMediaSource(iface); CHECK_EXPECT(test_source_BeginGetEvent); - return source->begin_get_event_res; + if (source->begin_get_event_hr == S_OK) + return IMFMediaEventQueue_BeginGetEvent(source->queue, callback, state); + else return source->begin_get_event_hr; }
static HRESULT WINAPI test_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + struct test_source *source = impl_from_IMFMediaSource(iface); + CHECK_EXPECT(test_source_EndGetEvent); + + if (source->end_get_event_hr == S_OK) + return IMFMediaEventQueue_EndGetEvent(source->queue, result, event); + else { + *event = NULL; + return source->end_get_event_hr; + } }
static HRESULT WINAPI test_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) { + struct test_source *source = impl_from_IMFMediaSource(iface); CHECK_EXPECT(test_source_QueueEvent); - return E_NOTIMPL; + + if (source->queue_event_hr == S_OK) + return IMFMediaEventQueue_QueueEventParamVar(source->queue, event_type, ext_type, hr, value); + else return source->queue_event_hr; }
static HRESULT WINAPI test_source_GetCharacteristics(IMFMediaSource *iface, DWORD *flags) @@ -367,8 +379,14 @@ static HRESULT WINAPI test_source_CreatePresentationDescriptor(IMFMediaSource *i static HRESULT WINAPI test_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *pd, const GUID *time_format, const PROPVARIANT *start_position) { + struct test_source *source = impl_from_IMFMediaSource(iface); CHECK_EXPECT(test_source_Start); - return E_NOTIMPL; + if (source->start_hr == S_OK) + { + IMFMediaEventQueue_QueueEventParamUnk(source->queue, MESourceStarted, &GUID_NULL, S_OK, NULL); + return S_OK; + } + else return source->start_hr; }
static HRESULT WINAPI test_source_Stop(IMFMediaSource *iface) @@ -413,12 +431,25 @@ static IMFMediaSource *create_test_source(IMFPresentationDescriptor *pd) source = calloc(1, sizeof(*source)); source->IMFMediaSource_iface.lpVtbl = &test_source_vtbl; source->refcount = 1; - source->begin_get_event_res = E_NOTIMPL; + source->begin_get_event_hr = E_NOTIMPL; + source->end_get_event_hr = E_NOTIMPL; + source->queue_event_hr = E_NOTIMPL; + source->start_hr = E_NOTIMPL; + MFCreateEventQueue(&source->queue); IMFPresentationDescriptor_AddRef((source->pd = pd));
return &source->IMFMediaSource_iface; }
+static void test_media_source_reinitialize_queue(IMFMediaSource *iface) +{ + struct test_source *source = impl_from_IMFMediaSource(iface); + + IMFMediaEventQueue_Shutdown(source->queue); + IMFMediaEventQueue_Release(source->queue); + MFCreateEventQueue(&source->queue); +} + static HRESULT WINAPI test_unk_QueryInterface(IUnknown *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IUnknown)) @@ -2495,6 +2526,9 @@ static void test_media_session_events(void) /* test IMFMediaSession_Start with source returning an error in BeginGetEvent */ source_impl = impl_from_IMFMediaSource(source);
+ source_impl->begin_get_event_hr = 0x80001234; + source_impl->end_get_event_hr = MF_E_SHUTDOWN; + source_impl->start_hr = MF_E_SHUTDOWN; hr = MFCreateMediaSession(NULL, &session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
@@ -2506,34 +2540,27 @@ static void test_media_session_events(void) ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); PropVariantClear(&propvar);
- source_impl->begin_get_event_res = 0x80001234; - SET_EXPECT(test_source_BeginGetEvent); - SET_EXPECT(test_source_QueueEvent); - SET_EXPECT(test_source_Start); - propvar.vt = VT_EMPTY; hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = wait_media_event_until_blocking(session, callback, MESessionStarted, 1000, &propvar); ok(hr == 0x80001234, "Unexpected hr %#lx.\n", hr); ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); - ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); - PropVariantClear(&propvar); - CHECK_CALLED(test_source_BeginGetEvent); - CHECK_NOT_CALLED(test_source_Start);
+ SET_EXPECT(test_source_QueueEvent); hr = IMFMediaSession_ClearTopologies(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt);
hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(media_sink.shutdown, "media sink didn't shutdown.\n"); media_sink.shutdown = FALSE;
- source_impl->begin_get_event_res = E_NOTIMPL; - CLEAR_CALLED(test_source_BeginGetEvent); CLEAR_CALLED(test_source_QueueEvent); CLEAR_CALLED(test_source_Start); @@ -2554,18 +2581,18 @@ static void test_media_session_events(void) ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); PropVariantClear(&propvar);
- source_impl = impl_from_IMFMediaSource(source); - source_impl->begin_get_event_res = S_OK; + source_impl->begin_get_event_hr = S_OK; + source_impl->end_get_event_hr = MF_E_SHUTDOWN; + source_impl->start_hr = 0x80001234;
SET_EXPECT(test_source_BeginGetEvent); - SET_EXPECT(test_source_QueueEvent); SET_EXPECT(test_source_Start);
propvar.vt = VT_EMPTY; hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = wait_media_event_until_blocking(session, callback, MESessionStarted, 1000, &propvar); - ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr); + ok(hr == 0x80001234, "Unexpected hr %#lx.\n", hr); ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); PropVariantClear(&propvar); @@ -2576,17 +2603,74 @@ static void test_media_session_events(void) hr = IMFMediaSession_ClearTopologies(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ SET_EXPECT(test_source_QueueEvent); hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(media_sink.shutdown, "media sink didn't shutdown.\n"); media_sink.shutdown = FALSE;
- source_impl->begin_get_event_res = E_NOTIMPL; - CLEAR_CALLED(test_source_BeginGetEvent); CLEAR_CALLED(test_source_QueueEvent); CLEAR_CALLED(test_source_Start);
+ test_media_source_reinitialize_queue(source); + + /* sometimes briefly leaking */ + IMFMediaSession_Release(session); + + + /* test IMFMediaSession_Start when event queue fails. */ + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaSession_SetTopology(session, 0, topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); + ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); + PropVariantClear(&propvar); + + SET_EXPECT(test_source_BeginGetEvent); + SET_EXPECT(test_source_EndGetEvent); + SET_EXPECT(test_source_Start); + source_impl->begin_get_event_hr = S_OK; + source_impl->end_get_event_hr = 0x80001234; + source_impl->start_hr = S_OK; + propvar.vt = VT_EMPTY; + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event_until_blocking(session, callback, MEError, 1000, &propvar); + todo_wine ok(hr == 0x80001234, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + CHECK_CALLED(test_source_BeginGetEvent); + CHECK_CALLED(test_source_EndGetEvent); + CHECK_CALLED(test_source_Start); + + source_impl->begin_get_event_hr = MF_E_SHUTDOWN; + propvar.vt = VT_EMPTY; + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + hr = wait_media_event_until_blocking(session, callback, MESessionStarted, 1000, &propvar); + ok(hr == WAIT_TIMEOUT, "Unexpected hr %#lx.\n", hr); /* New commands are not handled */ + + hr = IMFMediaSession_ClearTopologies(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSession_BeginGetEvent(session, callback, NULL); + ok(hr == MF_S_MULTIPLE_BEGIN || hr == MF_E_MULTIPLE_BEGIN /* Win 7 */, "Unexpected hr %#lx\n", hr); + + SET_EXPECT(test_source_QueueEvent); + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(media_sink.shutdown, "media sink didn't shutdown.\n"); + media_sink.shutdown = FALSE; + + test_media_source_reinitialize_queue(source); + + hr = IMFMediaEventQueue_Shutdown(source_impl->queue); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + /* sometimes briefly leaking */ IMFMediaSession_Release(session);
From: Santino Mazza smazza@codeweavers.com
--- dlls/mf/tests/mf.c | 834 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 701 insertions(+), 133 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 1e46897bac8..07e989e577f 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -265,8 +265,171 @@ static void init_sink_node(IMFStreamSink *stream_sink, MF_CONNECT_METHOD method, } }
+struct test_media_stream +{ + IMFMediaStream IMFMediaStream_iface; + IMFMediaEventQueue *queue; + IMFStreamDescriptor *sd; + IMFMediaSource *source; + LONG refcount; + HRESULT request_sample_hr; +}; + +static struct test_media_stream *impl_from_IMFMediaStream(IMFMediaStream *iface) +{ + return CONTAINING_RECORD(iface, struct test_media_stream, IMFMediaStream_iface); +} + +static HRESULT WINAPI test_media_stream_QueryInterface(IMFMediaStream *iface, REFIID riid, void **out) +{ + if (IsEqualIID(riid, &IID_IMFMediaStream) || + (IsEqualIID(riid, &IID_IMFMediaEventGenerator)) || + IsEqualIID(riid, &IID_IUnknown)) + { + IMFMediaStream_AddRef((*out = iface)); + return S_OK; + } + + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_media_stream_AddRef(IMFMediaStream *iface) +{ + struct test_media_stream *stream = impl_from_IMFMediaStream(iface); + return InterlockedIncrement(&stream->refcount); +} + +static ULONG WINAPI test_media_stream_Release(IMFMediaStream *iface) +{ + struct test_media_stream *stream = impl_from_IMFMediaStream(iface); + ULONG refcount; + + refcount = InterlockedDecrement(&stream->refcount); + if (refcount == 0) + { + IMFMediaEventQueue_Release(stream->queue); + IMFMediaSource_Release(stream->source); + IMFStreamDescriptor_Release(stream->sd); + free(stream); + } + + return refcount; +} + +static HRESULT WINAPI test_media_stream_GetEvent(IMFMediaStream *iface, DWORD flags, IMFMediaEvent **event) +{ + struct test_media_stream *stream = impl_from_IMFMediaStream(iface); + return IMFMediaEventQueue_GetEvent(stream->queue, flags, event); +} + +static HRESULT WINAPI test_media_stream_BeginGetEvent(IMFMediaStream *iface, IMFAsyncCallback *callback, IUnknown *unk) +{ + struct test_media_stream *stream = impl_from_IMFMediaStream(iface); + return IMFMediaEventQueue_BeginGetEvent(stream->queue, callback, unk); +} + +static HRESULT WINAPI test_media_stream_EndGetEvent(IMFMediaStream *iface, IMFAsyncResult *result, IMFMediaEvent **event) +{ + struct test_media_stream *stream = impl_from_IMFMediaStream(iface); + return IMFMediaEventQueue_EndGetEvent(stream->queue, result, event); +} + +static HRESULT WINAPI test_media_stream_QueueEvent(IMFMediaStream *iface, MediaEventType met, REFGUID type, HRESULT hr, const PROPVARIANT *pv) +{ + struct test_media_stream *stream = impl_from_IMFMediaStream(iface); + return IMFMediaEventQueue_QueueEventParamVar(stream->queue, met, type, hr, pv); +} + +static HRESULT WINAPI test_media_stream_GetMediaSource(IMFMediaStream *iface, IMFMediaSource **source) +{ + struct test_media_stream *stream = impl_from_IMFMediaStream(iface); + todo_wine ok(0, "Call not expected\n"); + IMFMediaSource_AddRef(stream->source); + *source = stream->source; + return S_OK; +} + +static HRESULT WINAPI test_media_stream_GetStreamDescriptor(IMFMediaStream *iface, IMFStreamDescriptor **descriptor) +{ + struct test_media_stream *stream = impl_from_IMFMediaStream(iface); + + IMFStreamDescriptor_AddRef(stream->sd); + *descriptor = stream->sd; + return S_OK; +} + +static HRESULT WINAPI test_media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token) +{ + struct test_media_stream *stream = impl_from_IMFMediaStream(iface); + IMFSample *sample; + IMFMediaBuffer *buffer; + + if (stream->request_sample_hr != S_OK) return stream->request_sample_hr; + + MFCreateSample(&sample); + MFCreateMemoryBuffer(4, &buffer); + IMFMediaBuffer_SetCurrentLength(buffer, 4); + IMFSample_SetSampleTime(sample, 0); + IMFSample_SetSampleDuration(sample, 1); + IMFSample_AddBuffer(sample, buffer); + if (token) + IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token); + IMFMediaEventQueue_QueueEventParamUnk(stream->queue, MEMediaSample, &GUID_NULL, S_OK, (IUnknown*)sample); + IMFSample_Release(sample); + IMFMediaBuffer_Release(buffer); + return S_OK; +} + +static const IMFMediaStreamVtbl test_media_stream_vtbl = +{ + test_media_stream_QueryInterface, + test_media_stream_AddRef, + test_media_stream_Release, + test_media_stream_GetEvent, + test_media_stream_BeginGetEvent, + test_media_stream_EndGetEvent, + test_media_stream_QueueEvent, + test_media_stream_GetMediaSource, + test_media_stream_GetStreamDescriptor, + test_media_stream_RequestSample, +}; + +static void start_media_stream(IMFMediaStream *iface) +{ + struct test_media_stream *stream = impl_from_IMFMediaStream(iface); + + IMFMediaEventQueue_QueueEventParamUnk(stream->queue, MEStreamStarted, &GUID_NULL, S_OK, NULL); +} + +static struct test_media_stream *create_test_media_stream(IMFStreamDescriptor *sd, IMFMediaSource *source) +{ + struct test_media_stream *stream; + + stream = calloc(1, sizeof(*stream)); + stream->IMFMediaStream_iface.lpVtbl = &test_media_stream_vtbl; + stream->refcount = 1; + + if (sd) + { + IMFStreamDescriptor_AddRef(sd); + stream->sd = sd; + } + + if (source) + { + IMFMediaSource_AddRef(source); + stream->source = source; + } + + MFCreateEventQueue(&stream->queue); + + return stream; +} + DEFINE_EXPECT(test_source_BeginGetEvent); DEFINE_EXPECT(test_source_EndGetEvent); +DEFINE_EXPECT(test_source_GetEvent); DEFINE_EXPECT(test_source_QueueEvent); DEFINE_EXPECT(test_source_Start);
@@ -278,6 +441,7 @@ struct test_source HRESULT begin_get_event_hr, end_get_event_hr, start_hr, queue_event_hr; IMFPresentationDescriptor *pd; + struct test_media_stream *stream; };
static struct test_source *impl_from_IMFMediaSource(IMFMediaSource *iface) @@ -316,7 +480,6 @@ static ULONG WINAPI test_source_Release(IMFMediaSource *iface)
if (!refcount) { - IMFMediaEventQueue_Shutdown(source->queue); IMFMediaEventQueue_Release(source->queue); IMFPresentationDescriptor_Release(source->pd); free(source); @@ -327,8 +490,9 @@ static ULONG WINAPI test_source_Release(IMFMediaSource *iface)
static HRESULT WINAPI test_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + struct test_source *source = impl_from_IMFMediaSource(iface); + CHECK_EXPECT(test_source_GetEvent); + return IMFMediaEventQueue_GetEvent(source->queue, flags, event); }
static HRESULT WINAPI test_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state) @@ -380,9 +544,25 @@ static HRESULT WINAPI test_source_Start(IMFMediaSource *iface, IMFPresentationDe const PROPVARIANT *start_position) { struct test_source *source = impl_from_IMFMediaSource(iface); + IMFStreamDescriptor *sd; + struct test_media_stream *stream; + BOOL selected; + CHECK_EXPECT(test_source_Start); if (source->start_hr == S_OK) { + if (source->stream) + { + IMFMediaEventQueue_Shutdown(source->stream->queue); + IMFMediaStream_Release(&source->stream->IMFMediaStream_iface); + } + IMFPresentationDescriptor_GetStreamDescriptorByIndex(source->pd, 0, &selected, &sd); + stream = create_test_media_stream(sd, iface); + source->stream = stream; + IMFStreamDescriptor_Release(sd); + + IMFMediaEventQueue_QueueEventParamUnk(source->queue, MENewStream, &GUID_NULL, S_OK, (IUnknown*)&stream->IMFMediaStream_iface); + start_media_stream(&stream->IMFMediaStream_iface); IMFMediaEventQueue_QueueEventParamUnk(source->queue, MESourceStarted, &GUID_NULL, S_OK, NULL); return S_OK; } @@ -403,8 +583,11 @@ static HRESULT WINAPI test_source_Pause(IMFMediaSource *iface)
static HRESULT WINAPI test_source_Shutdown(IMFMediaSource *iface) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + struct test_source *source = impl_from_IMFMediaSource(iface); + IMFMediaEventQueue_Shutdown(source->queue); + IMFMediaEventQueue_Shutdown(source->stream->queue); + IMFMediaStream_Release(&source->stream->IMFMediaStream_iface); + return S_OK; }
static const IMFMediaSourceVtbl test_source_vtbl = @@ -1647,9 +1830,194 @@ static const IMFMediaTypeHandlerVtbl test_handler_vtbl =
static const struct test_handler test_handler = {.IMFMediaTypeHandler_iface.lpVtbl = &test_handler_vtbl};
+struct test_stream_sink +{ + IMFStreamSink IMFStreamSink_iface; + LONG refcount; + IMFMediaEventQueue *queue; + IMFMediaTypeHandler *handler; + IMFMediaSink *media_sink; +}; + +static struct test_stream_sink *impl_from_IMFStreamSink(IMFStreamSink *iface) +{ + return CONTAINING_RECORD(iface, struct test_stream_sink, IMFStreamSink_iface); +} + +static HRESULT WINAPI test_stream_sink_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFStreamSink) + || IsEqualIID(riid, &IID_IMFMediaEventGenerator) + || IsEqualIID(riid, &IID_IUnknown)) + { + IMFStreamSink_AddRef((*obj = iface)); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_stream_sink_AddRef(IMFStreamSink *iface) +{ + struct test_stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + return InterlockedIncrement(&stream_sink->refcount); +} + +static ULONG WINAPI test_stream_sink_Release(IMFStreamSink *iface) +{ + struct test_stream_sink *stream = impl_from_IMFStreamSink(iface); + ULONG refcount; + + refcount = InterlockedDecrement(&stream->refcount); + + if (refcount == 0) + { + if (stream->queue) + IMFMediaEventQueue_Release(stream->queue); + if (stream->handler) + IMFMediaTypeHandler_Release(stream->handler); + if (stream->media_sink) + IMFMediaSink_Release(stream->media_sink); + free(stream); + } + + return refcount; +} + +static HRESULT WINAPI test_stream_sink_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event) +{ + struct test_stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + return IMFMediaEventQueue_GetEvent(stream_sink->queue, flags, event); +} + +static HRESULT WINAPI test_stream_sink_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback, IUnknown *state) +{ + struct test_stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + return IMFMediaEventQueue_BeginGetEvent(stream_sink->queue, callback, state); +} + +static HRESULT WINAPI test_stream_sink_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result, + IMFMediaEvent **event) +{ + struct test_stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + return IMFMediaEventQueue_EndGetEvent(stream_sink->queue, result, event); +} + +static HRESULT WINAPI test_stream_sink_QueueEvent(IMFStreamSink *iface, MediaEventType event_type, + REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) +{ + struct test_stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + return IMFMediaEventQueue_QueueEventParamVar(stream_sink->queue, event_type, ext_type, hr, value); +} + +static HRESULT WINAPI test_stream_sink_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **sink) +{ + struct test_stream_sink *impl = impl_from_IMFStreamSink(iface); + + if (impl->media_sink) + { + IMFMediaSink_AddRef((*sink = impl->media_sink)); + return S_OK; + } + + todo_wine + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_stream_sink_GetIdentifier(IMFStreamSink *iface, DWORD *id) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_stream_sink_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler) +{ + struct test_stream_sink *impl = impl_from_IMFStreamSink(iface); + + if (impl->handler) + { + IMFMediaTypeHandler_AddRef((*handler = impl->handler)); + return S_OK; + } + + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_stream_sink_ProcessSample(IMFStreamSink *iface, IMFSample *sample) +{ + IMFStreamSink_QueueEvent(iface, MEStreamSinkRequestSample, &GUID_NULL, S_OK, NULL); + return S_OK; +} + +static HRESULT WINAPI test_stream_sink_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type, + const PROPVARIANT *marker_value, const PROPVARIANT *context) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_stream_sink_Flush(IMFStreamSink *iface) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static const IMFStreamSinkVtbl test_stream_sink_vtbl = +{ + test_stream_sink_QueryInterface, + test_stream_sink_AddRef, + test_stream_sink_Release, + test_stream_sink_GetEvent, + test_stream_sink_BeginGetEvent, + test_stream_sink_EndGetEvent, + test_stream_sink_QueueEvent, + test_stream_sink_GetMediaSink, + test_stream_sink_GetIdentifier, + test_stream_sink_GetMediaTypeHandler, + test_stream_sink_ProcessSample, + test_stream_sink_PlaceMarker, + test_stream_sink_Flush, +}; + +static struct test_stream_sink *create_test_stream_sink(IMFMediaSink *media_sink, IMFMediaTypeHandler *handler) +{ + struct test_stream_sink *stream_sink; + + stream_sink = calloc(1, sizeof(*stream_sink)); + stream_sink->refcount = 1; + + stream_sink->IMFStreamSink_iface.lpVtbl = &test_stream_sink_vtbl; + + if (media_sink) + { + IMFMediaSink_AddRef(media_sink); + stream_sink->media_sink = media_sink; + } + + if (handler) + { + IMFMediaTypeHandler_AddRef(handler); + stream_sink->handler = handler; + } + + MFCreateEventQueue(&stream_sink->queue); + + return stream_sink; +} + + struct test_media_sink { IMFMediaSink IMFMediaSink_iface; + IMFMediaEventGenerator IMFMediaEventGenerator_iface; + IMFClockStateSink IMFClockStateSink_iface; + LONG refcount; + struct test_stream_sink *stream; + IMFMediaEventQueue *queue; + IMFPresentationClock *clock; BOOL shutdown; };
@@ -1658,27 +2026,65 @@ static struct test_media_sink *impl_from_IMFMediaSink(IMFMediaSink *iface) return CONTAINING_RECORD(iface, struct test_media_sink, IMFMediaSink_iface); }
+static struct test_media_sink *impl_from_IMFClockStateSink(IMFClockStateSink *iface) +{ + return CONTAINING_RECORD(iface, struct test_media_sink, IMFClockStateSink_iface); +} + +static struct test_media_sink *impl_from_IMFMediaEventGenerator(IMFMediaEventGenerator *iface) +{ + return CONTAINING_RECORD(iface, struct test_media_sink, IMFMediaEventGenerator_iface); +} + + static HRESULT WINAPI test_media_sink_QueryInterface(IMFMediaSink *iface, REFIID riid, void **obj) { + struct test_media_sink *sink = impl_from_IMFMediaSink(iface); + if (IsEqualIID(riid, &IID_IMFMediaSink) || IsEqualIID(riid, &IID_IUnknown)) { IMFMediaSink_AddRef((*obj = iface)); - return S_OK; + } + else if (IsEqualIID(riid, &IID_IMFMediaEventGenerator)) + { + IMFMediaEventGenerator_AddRef((*obj = &sink->IMFMediaEventGenerator_iface)); + } + else if (IsEqualIID(riid, &IID_IMFClockStateSink)) + { + IMFClockStateSink_AddRef((*obj = &sink->IMFClockStateSink_iface)); + } + else + { + *obj = NULL; + return E_NOINTERFACE; }
- *obj = NULL; - return E_NOINTERFACE; + return S_OK; }
static ULONG WINAPI test_media_sink_AddRef(IMFMediaSink *iface) { - return 2; + struct test_media_sink *sink = impl_from_IMFMediaSink(iface); + return InterlockedIncrement(&sink->refcount); }
static ULONG WINAPI test_media_sink_Release(IMFMediaSink *iface) { - return 1; + struct test_media_sink *sink = impl_from_IMFMediaSink(iface); + ULONG refcount; + + refcount = InterlockedDecrement(&sink->refcount); + if (refcount == 0) + { + if (sink->queue) + IMFMediaEventQueue_Release(sink->queue); + if (sink->clock) + IMFPresentationClock_Release(sink->clock); + free(sink); + } + + return refcount; }
static HRESULT WINAPI test_media_sink_GetCharacteristics(IMFMediaSink *iface, DWORD *characteristics) @@ -1702,14 +2108,16 @@ static HRESULT WINAPI test_media_sink_RemoveStreamSink(IMFMediaSink *iface, DWOR
static HRESULT WINAPI test_media_sink_GetStreamSinkCount(IMFMediaSink *iface, DWORD *count) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + *count = 1; + return S_OK; }
static HRESULT WINAPI test_media_sink_GetStreamSinkByIndex(IMFMediaSink *iface, DWORD index, IMFStreamSink **sink) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + struct test_media_sink *media_sink = impl_from_IMFMediaSink(iface); + IMFStreamSink_AddRef(&media_sink->stream->IMFStreamSink_iface); + *sink = &media_sink->stream->IMFStreamSink_iface; + return S_OK; }
static HRESULT WINAPI test_media_sink_GetStreamSinkById(IMFMediaSink *iface, DWORD stream_sink_id, IMFStreamSink **sink) @@ -1720,20 +2128,42 @@ static HRESULT WINAPI test_media_sink_GetStreamSinkById(IMFMediaSink *iface, DWO
static HRESULT WINAPI test_media_sink_SetPresentationClock(IMFMediaSink *iface, IMFPresentationClock *clock) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + struct test_media_sink *sink = impl_from_IMFMediaSink(iface); + + IMFPresentationClock_AddRef(clock); + sink->clock = clock; + IMFPresentationClock_AddClockStateSink(sink->clock, &sink->IMFClockStateSink_iface); + return S_OK; }
static HRESULT WINAPI test_media_sink_GetPresentationClock(IMFMediaSink *iface, IMFPresentationClock **clock) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + struct test_media_sink *sink = impl_from_IMFMediaSink(iface); + + if (sink->clock == NULL) + return MF_E_NO_CLOCK; + IMFPresentationClock_AddRef(sink->clock); + *clock = sink->clock; + return S_OK; }
static HRESULT WINAPI test_media_sink_Shutdown(IMFMediaSink *iface) { struct test_media_sink *sink = impl_from_IMFMediaSink(iface); ok(!sink->shutdown, "Unexpected call.\n"); + if (sink->clock) + IMFPresentationClock_Release(sink->clock); + sink->clock = NULL; + + if (sink->stream) + { + IMFMediaEventQueue_Shutdown(sink->stream->queue); + IMFStreamSink_Release(&sink->stream->IMFStreamSink_iface); + sink->stream = NULL; + } + + IMFMediaEventQueue_Shutdown(sink->queue); + sink->shutdown = TRUE; return S_OK; } @@ -1754,142 +2184,145 @@ static const IMFMediaSinkVtbl test_media_sink_vtbl = test_media_sink_Shutdown, };
-static const struct test_media_sink test_media_sink = {.IMFMediaSink_iface.lpVtbl = &test_media_sink_vtbl}; - -struct test_stream_sink +static HRESULT WINAPI test_media_sink_clock_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj) { - IMFStreamSink IMFStreamSink_iface; - IMFMediaTypeHandler *handler; - IMFMediaSink *media_sink; -}; - -static struct test_stream_sink *impl_from_IMFStreamSink(IMFStreamSink *iface) -{ - return CONTAINING_RECORD(iface, struct test_stream_sink, IMFStreamSink_iface); + struct test_media_sink *sink = impl_from_IMFClockStateSink(iface); + return IMFMediaSink_QueryInterface(&sink->IMFMediaSink_iface, riid, obj); }
-static HRESULT WINAPI test_stream_sink_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj) +static ULONG WINAPI test_media_sink_clock_sink_AddRef(IMFClockStateSink *iface) { - if (IsEqualIID(riid, &IID_IMFStreamSink) - || IsEqualIID(riid, &IID_IMFMediaEventGenerator) - || IsEqualIID(riid, &IID_IUnknown)) - { - IMFStreamSink_AddRef((*obj = iface)); - return S_OK; - } - - *obj = NULL; - return E_NOINTERFACE; + struct test_media_sink *sink = impl_from_IMFClockStateSink(iface); + return IMFMediaSink_AddRef(&sink->IMFMediaSink_iface); }
-static ULONG WINAPI test_stream_sink_AddRef(IMFStreamSink *iface) +static ULONG WINAPI test_media_sink_clock_sink_Release(IMFClockStateSink *iface) { - return 2; + struct test_media_sink *sink = impl_from_IMFClockStateSink(iface); + return IMFMediaSink_Release(&sink->IMFMediaSink_iface); }
-static ULONG WINAPI test_stream_sink_Release(IMFStreamSink *iface) +static HRESULT WINAPI test_media_sink_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME time, LONGLONG offset) { - return 1; + struct test_media_sink *sink = impl_from_IMFClockStateSink(iface); + + IMFStreamSink_QueueEvent(&sink->stream->IMFStreamSink_iface, MEStreamSinkStarted, &GUID_NULL, S_OK, NULL); + IMFStreamSink_QueueEvent(&sink->stream->IMFStreamSink_iface, MEStreamSinkRequestSample, &GUID_NULL, S_OK, NULL); + return S_OK; }
-static HRESULT WINAPI test_stream_sink_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event) +static HRESULT WINAPI test_media_sink_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME time) { - ok(0, "Unexpected call.\n"); + ok(0, "Unexpected call\n"); return E_NOTIMPL; }
-static HRESULT WINAPI test_stream_sink_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback, IUnknown *state) +static HRESULT WINAPI test_media_sink_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME time) { - ok(0, "Unexpected call.\n"); + ok(0, "Unexpected call\n"); return E_NOTIMPL; }
-static HRESULT WINAPI test_stream_sink_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result, - IMFMediaEvent **event) +static HRESULT WINAPI test_media_sink_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME time) { - ok(0, "Unexpected call.\n"); + ok(0, "Unexpected call\n"); return E_NOTIMPL; }
-static HRESULT WINAPI test_stream_sink_QueueEvent(IMFStreamSink *iface, MediaEventType event_type, - REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) +static HRESULT WINAPI test_media_sink_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME time, float rate) { - ok(0, "Unexpected call.\n"); + ok(0, "Unexpected call\n"); return E_NOTIMPL; }
-static HRESULT WINAPI test_stream_sink_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **sink) +static const IMFClockStateSinkVtbl test_media_sink_clock_sink_vtbl = { - struct test_stream_sink *impl = impl_from_IMFStreamSink(iface); - - if (impl->media_sink) - { - IMFMediaSink_AddRef((*sink = impl->media_sink)); - return S_OK; - } + test_media_sink_clock_sink_QueryInterface, + test_media_sink_clock_sink_AddRef, + test_media_sink_clock_sink_Release, + test_media_sink_clock_sink_OnClockStart, + test_media_sink_clock_sink_OnClockStop, + test_media_sink_clock_sink_OnClockPause, + test_media_sink_clock_sink_OnClockRestart, + test_media_sink_clock_sink_OnClockSetRate, +};
- todo_wine - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; +static HRESULT WINAPI test_media_sink_events_QueryInterface(IMFMediaEventGenerator *iface, REFIID riid, void **obj) +{ + struct test_media_sink *sink = impl_from_IMFMediaEventGenerator(iface); + return IMFMediaSink_QueryInterface(&sink->IMFMediaSink_iface, riid, obj); }
-static HRESULT WINAPI test_stream_sink_GetIdentifier(IMFStreamSink *iface, DWORD *id) +static ULONG WINAPI test_media_sink_events_AddRef(IMFMediaEventGenerator *iface) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + struct test_media_sink *sink = impl_from_IMFMediaEventGenerator(iface); + return IMFMediaSink_AddRef(&sink->IMFMediaSink_iface); }
-static HRESULT WINAPI test_stream_sink_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler) +static ULONG WINAPI test_media_sink_events_Release(IMFMediaEventGenerator *iface) { - struct test_stream_sink *impl = impl_from_IMFStreamSink(iface); - - if (impl->handler) - { - IMFMediaTypeHandler_AddRef((*handler = impl->handler)); - return S_OK; - } + struct test_media_sink *sink = impl_from_IMFMediaEventGenerator(iface); + return IMFMediaSink_Release(&sink->IMFMediaSink_iface); +}
- ok(0, "Unexpected call.\n"); +static HRESULT WINAPI test_media_sink_events_GetEvent(IMFMediaEventGenerator *iface, DWORD flags, IMFMediaEvent **event) +{ return E_NOTIMPL; }
-static HRESULT WINAPI test_stream_sink_ProcessSample(IMFStreamSink *iface, IMFSample *sample) +static HRESULT WINAPI test_media_sink_events_BeginGetEvent(IMFMediaEventGenerator *iface, IMFAsyncCallback *callback, IUnknown *unk) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + struct test_media_sink *sink = impl_from_IMFMediaEventGenerator(iface); + return IMFMediaEventQueue_BeginGetEvent(sink->queue, callback, unk); }
-static HRESULT WINAPI test_stream_sink_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type, - const PROPVARIANT *marker_value, const PROPVARIANT *context) +static HRESULT WINAPI test_media_sink_events_EndGetEvent(IMFMediaEventGenerator *iface, IMFAsyncResult *result, IMFMediaEvent **event) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + struct test_media_sink *sink = impl_from_IMFMediaEventGenerator(iface); + return IMFMediaEventQueue_EndGetEvent(sink->queue, result, event); }
-static HRESULT WINAPI test_stream_sink_Flush(IMFStreamSink *iface) +static HRESULT WINAPI test_media_sink_events_QueueEvent(IMFMediaEventGenerator *iface, MediaEventType met, REFGUID type, HRESULT hr, const PROPVARIANT *var) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + struct test_media_sink *sink = impl_from_IMFMediaEventGenerator(iface); + return IMFMediaEventQueue_QueueEventParamVar(sink->queue, met, type, hr, var); }
-static const IMFStreamSinkVtbl test_stream_sink_vtbl = +static const IMFMediaEventGeneratorVtbl test_media_sink_events_vtbl = { - test_stream_sink_QueryInterface, - test_stream_sink_AddRef, - test_stream_sink_Release, - test_stream_sink_GetEvent, - test_stream_sink_BeginGetEvent, - test_stream_sink_EndGetEvent, - test_stream_sink_QueueEvent, - test_stream_sink_GetMediaSink, - test_stream_sink_GetIdentifier, - test_stream_sink_GetMediaTypeHandler, - test_stream_sink_ProcessSample, - test_stream_sink_PlaceMarker, - test_stream_sink_Flush, + test_media_sink_events_QueryInterface, + test_media_sink_events_AddRef, + test_media_sink_events_Release, + test_media_sink_events_GetEvent, + test_media_sink_events_BeginGetEvent, + test_media_sink_events_EndGetEvent, + test_media_sink_events_QueueEvent, };
-static const struct test_stream_sink test_stream_sink = {.IMFStreamSink_iface.lpVtbl = &test_stream_sink_vtbl}; +static void test_media_sink_reinitialize(struct test_media_sink *media_sink, IMFMediaTypeHandler *handler) +{ + media_sink->shutdown = FALSE; + MFCreateEventQueue(&media_sink->queue); + media_sink->stream = create_test_stream_sink(&media_sink->IMFMediaSink_iface, handler); +} + +static struct test_media_sink *create_test_media_sink(IMFMediaTypeHandler *handler) { + struct test_media_sink *sink; + + sink = calloc(1, sizeof(*sink)); + sink->refcount = 1; + + sink->IMFMediaSink_iface.lpVtbl = &test_media_sink_vtbl; + sink->IMFMediaEventGenerator_iface.lpVtbl = &test_media_sink_events_vtbl; + sink->IMFClockStateSink_iface.lpVtbl = &test_media_sink_clock_sink_vtbl; + + sink->stream = create_test_stream_sink(&sink->IMFMediaSink_iface, handler); + + MFCreateEventQueue(&sink->queue); + + return sink; +} +
struct test_callback { @@ -1966,6 +2399,7 @@ static HRESULT WINAPI testcallback_Invoke(IMFAsyncCallback *iface, IMFAsyncResul
hr = IMFAsyncResult_GetState(result, &object); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (!object) return S_OK; hr = IMFMediaEventGenerator_EndGetEvent((IMFMediaEventGenerator *)object, result, &callback->media_event); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -2140,14 +2574,14 @@ static void test_media_session_events(void) ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 2 * 8), };
- struct test_stream_sink stream_sink = test_stream_sink; - struct test_media_sink media_sink = test_media_sink; struct test_handler handler = test_handler; struct test_source *source_impl; + struct test_media_sink *media_sink; IMFAsyncCallback *callback, *callback2; IMFMediaType *input_type, *output_type; IMFTopologyNode *src_node, *sink_node; IMFPresentationDescriptor *pd; + MFCLOCK_STATE clock_status; IMFMediaSession *session; IMFStreamDescriptor *sd; IMFAsyncResult *result; @@ -2158,8 +2592,8 @@ static void test_media_session_events(void) HRESULT hr; ULONG ref;
- stream_sink.handler = &handler.IMFMediaTypeHandler_iface; - stream_sink.media_sink = &media_sink.IMFMediaSink_iface; + + media_sink = create_test_media_sink(&handler.IMFMediaTypeHandler_iface);
hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); ok(hr == S_OK, "Startup failure, hr %#lx.\n", hr); @@ -2287,7 +2721,7 @@ static void test_media_session_events(void)
hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &sink_node); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - init_sink_node(&stream_sink.IMFStreamSink_iface, -1, sink_node); + init_sink_node(&media_sink->stream->IMFStreamSink_iface, -1, sink_node);
hr = MFCreateMediaType(&output_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -2325,8 +2759,12 @@ static void test_media_session_events(void)
hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(!media_sink.shutdown, "media sink is shutdown.\n"); - media_sink.shutdown = FALSE; + ok(!media_sink->shutdown, "media sink is shutdown.\n"); + if (media_sink->shutdown) + { + test_media_sink_reinitialize(media_sink, &handler.IMFMediaTypeHandler_iface); + init_sink_node(&media_sink->stream->IMFStreamSink_iface, -1, sink_node); + }
/* sometimes briefly leaking */ IMFMediaSession_Release(session); @@ -2363,8 +2801,9 @@ static void test_media_session_events(void)
hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(media_sink.shutdown, "media sink didn't shutdown.\n"); - media_sink.shutdown = FALSE; + ok(media_sink->shutdown, "media sink didn't shutdown.\n"); + test_media_sink_reinitialize(media_sink, &handler.IMFMediaTypeHandler_iface); + init_sink_node(&media_sink->stream->IMFStreamSink_iface, -1, sink_node);
/* sometimes briefly leaking */ IMFMediaSession_Release(session); @@ -2400,8 +2839,9 @@ static void test_media_session_events(void)
hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(media_sink.shutdown, "media sink didn't shutdown.\n"); - media_sink.shutdown = FALSE; + ok(media_sink->shutdown, "media sink didn't shutdown.\n"); + test_media_sink_reinitialize(media_sink, &handler.IMFMediaTypeHandler_iface); + init_sink_node(&media_sink->stream->IMFStreamSink_iface, -1, sink_node);
/* sometimes briefly leaking */ IMFMediaSession_Release(session); @@ -2438,8 +2878,9 @@ static void test_media_session_events(void)
hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(media_sink.shutdown, "media sink didn't shutdown.\n"); - media_sink.shutdown = FALSE; + ok(media_sink->shutdown, "media sink didn't shutdown.\n"); + test_media_sink_reinitialize(media_sink, &handler.IMFMediaTypeHandler_iface); + init_sink_node(&media_sink->stream->IMFStreamSink_iface, -1, sink_node);
/* sometimes briefly leaking */ IMFMediaSession_Release(session); @@ -2477,8 +2918,9 @@ static void test_media_session_events(void)
hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(media_sink.shutdown, "media sink didn't shutdown.\n"); - media_sink.shutdown = FALSE; + ok(media_sink->shutdown, "media sink didn't shutdown.\n"); + test_media_sink_reinitialize(media_sink, &handler.IMFMediaTypeHandler_iface); + init_sink_node(&media_sink->stream->IMFStreamSink_iface, -1, sink_node);
/* sometimes briefly leaking */ IMFMediaSession_Release(session); @@ -2516,8 +2958,9 @@ static void test_media_session_events(void)
hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(media_sink.shutdown, "media sink didn't shutdown.\n"); - media_sink.shutdown = FALSE; + ok(media_sink->shutdown, "media sink didn't shutdown.\n"); + test_media_sink_reinitialize(media_sink, &handler.IMFMediaTypeHandler_iface); + init_sink_node(&media_sink->stream->IMFStreamSink_iface, -1, sink_node);
/* sometimes briefly leaking */ IMFMediaSession_Release(session); @@ -2558,8 +3001,9 @@ static void test_media_session_events(void)
hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(media_sink.shutdown, "media sink didn't shutdown.\n"); - media_sink.shutdown = FALSE; + ok(media_sink->shutdown, "media sink didn't shutdown.\n"); + test_media_sink_reinitialize(media_sink, &handler.IMFMediaTypeHandler_iface); + init_sink_node(&media_sink->stream->IMFStreamSink_iface, -1, sink_node);
CLEAR_CALLED(test_source_BeginGetEvent); CLEAR_CALLED(test_source_QueueEvent); @@ -2606,14 +3050,16 @@ static void test_media_session_events(void) SET_EXPECT(test_source_QueueEvent); hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(media_sink.shutdown, "media sink didn't shutdown.\n"); - media_sink.shutdown = FALSE; + ok(media_sink->shutdown, "media sink didn't shutdown.\n"); + test_media_sink_reinitialize(media_sink, &handler.IMFMediaTypeHandler_iface); + init_sink_node(&media_sink->stream->IMFStreamSink_iface, -1, sink_node); + + test_media_source_reinitialize_queue(source);
CLEAR_CALLED(test_source_BeginGetEvent); CLEAR_CALLED(test_source_QueueEvent); CLEAR_CALLED(test_source_Start);
- test_media_source_reinitialize_queue(source);
/* sometimes briefly leaking */ IMFMediaSession_Release(session); @@ -2663,14 +3109,132 @@ static void test_media_session_events(void) SET_EXPECT(test_source_QueueEvent); hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(media_sink.shutdown, "media sink didn't shutdown.\n"); - media_sink.shutdown = FALSE; + ok(media_sink->shutdown, "media sink didn't shutdown.\n"); + test_media_sink_reinitialize(media_sink, &handler.IMFMediaTypeHandler_iface); + init_sink_node(&media_sink->stream->IMFStreamSink_iface, -1, sink_node); + + test_media_source_reinitialize_queue(source); + + /* sometimes briefly leaking */ + IMFMediaSession_Release(session); + + + /* test IMFMediaSession_Start when event queue fails. */ + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaSession_SetTopology(session, 0, topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); + ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); + PropVariantClear(&propvar); + + SET_EXPECT(test_source_BeginGetEvent); + SET_EXPECT(test_source_EndGetEvent); + SET_EXPECT(test_source_Start); + source_impl->begin_get_event_hr = S_OK; + source_impl->end_get_event_hr = S_OK; + source_impl->start_hr = S_OK; + propvar.vt = VT_EMPTY; + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event_until_blocking(session, callback, MESessionStarted, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + + hr = IMFPresentationClock_GetState(media_sink->clock, 0, &clock_status); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(clock_status == MFCLOCK_STATE_RUNNING, "Expected running got %d\n", clock_status); + + Sleep(1000); + SET_EXPECT(test_source_EndGetEvent); + source_impl->end_get_event_hr = MF_E_SHUTDOWN; + source_impl->queue_event_hr = S_OK; + hr = IMFMediaSource_QueueEvent(source, MESourceUnknown, &GUID_NULL, S_OK, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event_until_blocking(session, callback, MEError, 1000, &propvar); + todo_wine ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + CHECK_CALLED(test_source_BeginGetEvent); + CHECK_CALLED(test_source_EndGetEvent); + CHECK_CALLED(test_source_Start); + + hr = IMFPresentationClock_GetState(media_sink->clock, 0, &clock_status); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(clock_status == MFCLOCK_STATE_RUNNING, "Expected running got %d\n", clock_status); + + hr = IMFMediaSession_ClearTopologies(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + SET_EXPECT(test_source_QueueEvent); + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(media_sink->shutdown, "media sink didn't shutdown.\n"); + test_media_sink_reinitialize(media_sink, &handler.IMFMediaTypeHandler_iface); + init_sink_node(&media_sink->stream->IMFStreamSink_iface, -1, sink_node);
test_media_source_reinitialize_queue(source);
- hr = IMFMediaEventQueue_Shutdown(source_impl->queue); + /* sometimes briefly leaking */ + IMFMediaSession_Release(session); + + + /* Test media session when sample request fails while streaming. */ + hr = MFCreateMediaSession(NULL, &session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ hr = IMFMediaSession_SetTopology(session, 0, topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); + ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); + PropVariantClear(&propvar); + + SET_EXPECT(test_source_BeginGetEvent); + SET_EXPECT(test_source_EndGetEvent); + SET_EXPECT(test_source_Start); + source_impl->begin_get_event_hr = S_OK; + source_impl->end_get_event_hr = S_OK; + source_impl->start_hr = S_OK; + propvar.vt = VT_EMPTY; + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event_until_blocking(session, callback, MESessionStarted, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + ok(source_impl->stream != NULL, "Source stream is null\n"); + CHECK_CALLED(test_source_BeginGetEvent); + CHECK_CALLED(test_source_EndGetEvent); + CHECK_CALLED(test_source_Start); + + hr = IMFPresentationClock_GetState(media_sink->clock, 0, &clock_status); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(clock_status == MFCLOCK_STATE_RUNNING, "Expected running got %d\n", clock_status); + + Sleep(1000); + source_impl->stream->request_sample_hr = 0x80001234; + + hr = wait_media_event_until_blocking(session, callback, MEError, 1000, &propvar); + todo_wine ok(hr == 0x80001234, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + + hr = IMFPresentationClock_GetState(media_sink->clock, 0, &clock_status); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(clock_status == MFCLOCK_STATE_RUNNING, "Expected running got %d\n", clock_status); + + hr = IMFMediaSession_ClearTopologies(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + SET_EXPECT(test_source_EndGetEvent); + SET_EXPECT(test_source_GetEvent); + SET_EXPECT(test_source_QueueEvent); + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(media_sink->shutdown, "media sink didn't shutdown.\n"); + /* sometimes briefly leaking */ IMFMediaSession_Release(session);
@@ -2689,6 +3253,8 @@ static void test_media_session_events(void) ref = IMFTopology_Release(topology); ok(ref == 0, "Release returned %ld\n", ref);
+ IMFMediaSource_Shutdown(source); + IMFMediaSink_Release(&media_sink->IMFMediaSink_iface); ref = IMFMediaSource_Release(source); ok(ref == 0, "Release returned %ld\n", ref); ref = IMFPresentationDescriptor_Release(pd); @@ -3367,7 +3933,7 @@ static void test_topology_loader(void)
IMFTopologyNode *src_node, *sink_node, *src_node2, *sink_node2, *mft_node; IMFSampleGrabberSinkCallback *grabber_callback = create_test_grabber_callback(); - struct test_stream_sink stream_sink = test_stream_sink; + struct test_stream_sink *stream_sink; IMFMediaType *media_type, *input_type, *output_type; IMFTopology *topology, *topology2, *full_topology; struct test_handler handler = test_handler; @@ -3387,7 +3953,7 @@ static void test_topology_loader(void) BOOL ret; LONG ref;
- stream_sink.handler = &handler.IMFMediaTypeHandler_iface; + stream_sink = create_test_stream_sink(NULL, &handler.IMFMediaTypeHandler_iface);
hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); ok(hr == S_OK, "Startup failure, hr %#lx.\n", hr); @@ -3578,7 +4144,7 @@ static void test_topology_loader(void) source = create_test_source(pd);
init_source_node(source, test->source_method, src_node, pd, sd); - init_sink_node(&stream_sink.IMFStreamSink_iface, test->sink_method, sink_node); + init_sink_node(&stream_sink->IMFStreamSink_iface, test->sink_method, sink_node);
hr = IMFTopology_GetCount(topology, &count); ok(hr == S_OK, "Failed to get attribute count, hr %#lx.\n", hr); @@ -6654,7 +7220,7 @@ static void test_MFGetTopoNodeCurrentType(void) }; IMFMediaType *media_type, *input_types[2], *output_types[2]; IMFStreamDescriptor *input_descriptor, *output_descriptor; - struct test_stream_sink stream_sink = test_stream_sink; + struct test_stream_sink *stream_sink; IMFMediaTypeHandler *input_handler, *output_handler; IMFTransform *transform; IMFTopologyNode *node; @@ -6671,6 +7237,8 @@ static void test_MFGetTopoNodeCurrentType(void) hr = CoInitialize(NULL); ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr);
+ stream_sink = create_test_stream_sink(NULL, NULL); + hr = MFCreateMediaType(&input_types[0]); ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); init_media_type(input_types[0], media_type_desc, -1); @@ -6809,8 +7377,8 @@ static void test_MFGetTopoNodeCurrentType(void) hr = pMFGetTopoNodeCurrentType(node, 0, TRUE, &media_type); ok(hr == MF_E_INVALIDSTREAMNUMBER, "Unexpected hr %#lx.\n", hr);
- stream_sink.handler = output_handler; - hr = IMFTopologyNode_SetObject(node, (IUnknown *)&stream_sink.IMFStreamSink_iface); + stream_sink->handler = output_handler; + hr = IMFTopologyNode_SetObject(node, (IUnknown *)&stream_sink->IMFStreamSink_iface); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = pMFGetTopoNodeCurrentType(node, 0, FALSE, &media_type); ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#lx.\n", hr);
From: Santino Mazza smazza@codeweavers.com
--- dlls/mf/session.c | 7 ++++++- dlls/mf/tests/mf.c | 5 ++--- 2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index b5b631fb00a..2b3ac189ffb 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -3679,7 +3679,9 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM if (FAILED(hr = IMFMediaEventGenerator_EndGetEvent(event_source, result, &event))) { WARN("Failed to get event from %p, hr %#lx.\n", event_source, hr); - goto failed; + IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MEError, &GUID_NULL, hr, &value); + IMFMediaEventGenerator_Release(event_source); + return hr; }
if (FAILED(hr = IMFMediaEvent_GetType(event, &event_type))) @@ -3876,7 +3878,10 @@ failed: IMFMediaEvent_Release(event);
if (FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(event_source, iface, (IUnknown *)event_source))) + { WARN("Failed to re-subscribe, hr %#lx.\n", hr); + IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MEError, &GUID_NULL, hr, NULL); + }
IMFMediaEventGenerator_Release(event_source);
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 07e989e577f..c289101eb7b 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -3087,7 +3087,7 @@ static void test_media_session_events(void) hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = wait_media_event_until_blocking(session, callback, MEError, 1000, &propvar); - todo_wine ok(hr == 0x80001234, "Unexpected hr %#lx.\n", hr); + ok(hr == 0x80001234, "Unexpected hr %#lx.\n", hr); ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); CHECK_CALLED(test_source_BeginGetEvent); CHECK_CALLED(test_source_EndGetEvent); @@ -3097,7 +3097,6 @@ static void test_media_session_events(void) propvar.vt = VT_EMPTY; hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine hr = wait_media_event_until_blocking(session, callback, MESessionStarted, 1000, &propvar); ok(hr == WAIT_TIMEOUT, "Unexpected hr %#lx.\n", hr); /* New commands are not handled */
@@ -3155,7 +3154,7 @@ static void test_media_session_events(void) hr = IMFMediaSource_QueueEvent(source, MESourceUnknown, &GUID_NULL, S_OK, NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = wait_media_event_until_blocking(session, callback, MEError, 1000, &propvar); - todo_wine ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); CHECK_CALLED(test_source_BeginGetEvent); CHECK_CALLED(test_source_EndGetEvent);
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=138274
Your paranoid android.
=== w1064v1507 (64 bit report) ===
mf: mf.c:4950: Test failed: unexpected time difference 235. mf.c:3592: Test failed: WaitForSingleObject returned 0x102
=== w10pro64_zh_CN (64 bit report) ===
mf: mf.c:3258: Test failed: Release returned 4 mf.c:3260: Test failed: Release returned 4 mf.c:3262: Test failed: Release returned 4
Basically I implemented the interfaces needed for playback, and then modify the return value of each object. I tested for failures in EndGetEvent from the media source while streaming and also failures in RequestSample from media stream while streaming, in both I'm checking if there is a change in the state of the presentation clock.
Apparently, we are not handling correctly the RequestSample error case also.
On Mon Sep 11 16:08:35 2023 +0000, Nikolay Sivov wrote:
MEError is supposed to indicate fatal non-recoverable error. Have you checked what happens if you get this condition in the middle of the playback for example? I suspect such error reporting should happen in many more places, and we can work on this later, but right now it's useful to figure out if session gets into error state when this happens. Could you check what happens if End/BeginGetEvent() fails suddenly after a number of samples was successfully delivered and playback is still active? Should we stop the clock when this happens? Should we send first fatal error event only, or following failures are always reported with MEError? Note that 'value' is passed here uninitialized, if it's unused I believe you can use NULL.
This comment is not addressed as far as I can tell.
On Mon Oct 9 17:46:33 2023 +0000, Nikolay Sivov wrote:
This comment is not addressed as far as I can tell.
Woops.