-- v3: mf/session: Shut down all topologies on session shutdown. mf/session: Ensure the session object is shut down on release. mf/tests: Add tests for sample grabber sink shutdown. mf/tests: Check for sample grabber sink shutdown. mf/tests: Introduce a helper for creating an activated media sink.
From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/mf/tests/mf.c | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 0c0590ed195..69fd051b96a 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -3261,6 +3261,27 @@ static IMFSampleGrabberSinkCallback *create_test_grabber_callback(void) return &grabber->IMFSampleGrabberSinkCallback_iface; }
+static struct test_grabber_callback *create_activated_test_grabber_callback(IMFMediaType *output_type, + IMFStreamSink **stream_sink) +{ + struct test_grabber_callback *grabber_callback; + IMFActivate *sink_activate; + IMFMediaSink *sink; + HRESULT hr; + + grabber_callback = impl_from_IMFSampleGrabberSinkCallback(create_test_grabber_callback()); + hr = MFCreateSampleGrabberSinkActivate(output_type, &grabber_callback->IMFSampleGrabberSinkCallback_iface, &sink_activate); + ok(hr == S_OK, "Failed to create grabber sink, hr %#lx.\n", hr); + hr = IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&sink); + ok(hr == S_OK, "Failed to activate, hr %#lx.\n", hr); + IMFActivate_Release(sink_activate); + hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, stream_sink); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaSink_Release(sink); + + return grabber_callback; +} + static HRESULT WINAPI testshutdown_QueryInterface(IMFShutdown *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IMFShutdown) || @@ -6842,13 +6863,11 @@ static void test_h264_output_alignment(void) IMFTopology *topology, *resolved_topology; struct test_callback *test_callback; IMFMediaTypeHandler *handler; - IMFActivate *sink_activate; IMFTopoLoader *topo_loader; IMFStreamSink *stream_sink; IMFAsyncCallback *callback; IMFMediaType *output_type; IMFMediaSession *session; - IMFMediaSink *media_sink; IMFTransform *transform; IMFMediaSource *source; PROPVARIANT propvar; @@ -6868,21 +6887,15 @@ static void test_h264_output_alignment(void) return; }
- grabber_callback = impl_from_IMFSampleGrabberSinkCallback(create_test_grabber_callback()); - grabber_callback->ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); - ok(!!grabber_callback->ready_event, "CreateEventW failed, error %lu\n", GetLastError()); - hr = MFCreateMediaType(&output_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); init_media_type(output_type, video_nv12_desc, -1); - hr = MFCreateSampleGrabberSinkActivate(output_type, &grabber_callback->IMFSampleGrabberSinkCallback_iface, &sink_activate); - ok(hr == S_OK, "Failed to create grabber sink, hr %#lx.\n", hr); + + grabber_callback = create_activated_test_grabber_callback(output_type, &stream_sink); IMFMediaType_Release(output_type); + grabber_callback->ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(!!grabber_callback->ready_event, "CreateEventW failed, error %lu\n", GetLastError());
- IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&media_sink); - hr = IMFMediaSink_GetStreamSinkByIndex(media_sink, 0, &stream_sink); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - IMFActivate_Release(sink_activate); topology = create_test_topology_unk(source, (IUnknown *)stream_sink, NULL, NULL); hr = MFCreateTopoLoader(&topo_loader); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -6955,7 +6968,6 @@ static void test_h264_output_alignment(void) IMFAsyncCallback_Release(callback); IMFMediaSession_Release(session); IMFStreamSink_Release(stream_sink); - IMFMediaSink_Release(media_sink); IMFSampleGrabberSinkCallback_Release(&grabber_callback->IMFSampleGrabberSinkCallback_iface); IMFMediaSource_Release(source);
From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/mf/tests/mf.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 69fd051b96a..e8bf7f014b1 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -3113,6 +3113,8 @@ struct test_grabber_callback IMFCollection *samples; HANDLE ready_event; HANDLE done_event; + + BOOL shutdown; };
static struct test_grabber_callback *impl_from_IMFSampleGrabberSinkCallback(IMFSampleGrabberSinkCallback *iface) @@ -3227,6 +3229,8 @@ static HRESULT WINAPI test_grabber_callback_OnProcessSample(IMFSampleGrabberSink
static HRESULT WINAPI test_grabber_callback_OnShutdown(IMFSampleGrabberSinkCallback *iface) { + struct test_grabber_callback *grabber = impl_from_IMFSampleGrabberSinkCallback(iface); + grabber->shutdown = TRUE; return S_OK; }
@@ -4495,6 +4499,8 @@ static void test_sample_grabber_orientation(GUID subtype)
hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(grabber_callback->shutdown, "Media sink is not shut down.\n"); hr = IMFMediaSource_Shutdown(source); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFActivate_ShutdownObject(sink_activate); @@ -7116,12 +7122,15 @@ static void test_media_session_Start(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = wait_media_event(session, callback, MESessionClosed, 1000, &propvar); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!grabber_callback->shutdown, "Media sink was shut down.\n");
/* Media session is shut down */ hr = IMFMediaSource_Shutdown(source); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(grabber_callback->shutdown, "Media sink is not shut down.\n");
propvar.vt = VT_I8; propvar.hVal.QuadPart = 10000000; @@ -7200,8 +7209,11 @@ static void test_media_session_Start(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = wait_media_event(session, callback, MESessionClosed, 1000, &propvar); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!grabber_callback->shutdown, "Media sink was shut down.\n"); hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(grabber_callback->shutdown, "Media sink is not shut down.\n"); hr = IMFMediaSource_Shutdown(source); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
@@ -7413,6 +7425,7 @@ static void test_media_session_source_shutdown(void)
IMFMediaSource_Release(source);
+ ok(!grabber_callback->shutdown, "Media sink was shut down.\n"); IMFActivate_ShutdownObject(sink_activate); IMFActivate_Release(sink_activate); IMFSampleGrabberSinkCallback_Release(&grabber_callback->IMFSampleGrabberSinkCallback_iface); @@ -7646,6 +7659,8 @@ static void test_media_session_Close(void)
hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(grabber_callback->shutdown, "Media sink is not shut down.\n");
IMFPresentationClock_Release(presentation_clock); IMFAsyncCallback_Release(callback); @@ -7788,6 +7803,8 @@ static void test_media_session_thinning(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(grabber_callback->shutdown, "Media sink is not shut down.\n"); hr = IMFMediaSource_Shutdown(source); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/mf/tests/mf.c | 247 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 246 insertions(+), 1 deletion(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index e8bf7f014b1..cd02890a40c 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -4331,7 +4331,8 @@ static void test_sample_grabber_is_mediatype_supported(void) }
/* create a test topology with the specified source, sink, and option MFT. Return duration if required */ -static IMFTopology *create_test_topology_unk(IMFMediaSource *source, IUnknown *sink, IUnknown *mft, UINT64 *duration) +static IMFTopology *create_test_topology_unk_noshutdown(IMFMediaSource *source, IUnknown *sink, IUnknown *mft, + UINT64 *duration, UINT noshutdown_on_remove) { IMFTopologyNode *src_node, *sink_node, *mft_node; IMFPresentationDescriptor *pd; @@ -4383,6 +4384,11 @@ static IMFTopology *create_test_topology_unk(IMFMediaSource *source, IUnknown *s ok(hr == S_OK, "Failed to set object, hr %#lx.\n", hr); hr = IMFTopologyNode_SetUINT32(sink_node, &MF_TOPONODE_CONNECT_METHOD, MF_CONNECT_ALLOW_DECODER); ok(hr == S_OK, "Failed to set connect method, hr %#lx.\n", hr); + if (noshutdown_on_remove != UINT_MAX) + { + hr = IMFTopologyNode_SetUINT32(sink_node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, noshutdown_on_remove); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } hr = IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, TRUE); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
@@ -4393,6 +4399,11 @@ static IMFTopology *create_test_topology_unk(IMFMediaSource *source, IUnknown *s return topology; }
+static IMFTopology *create_test_topology_unk(IMFMediaSource *source, IUnknown *sink, IUnknown *mft, UINT64 *duration) +{ + return create_test_topology_unk_noshutdown(source, (IUnknown*)sink, mft, duration, UINT_MAX); +} + static IMFTopology *create_test_topology(IMFMediaSource *source, IMFActivate *sink_activate, UINT64 *duration) { return create_test_topology_unk(source, (IUnknown*)sink_activate, NULL, duration); @@ -8465,6 +8476,239 @@ static void test_media_session_seek(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); }
+static void test_media_session_sink_shutdown(void) +{ + media_type_desc video_rgb32_desc = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + }; + struct test_grabber_callback *grabber_callback, *grabber_callbacks[3]; + IMFAsyncCallback *callback; + IMFStreamSink *stream_sink; + IMFActivate *sink_activate; + IMFMediaType *output_type; + IMFMediaSession *session; + IMFMediaSource *source; + IMFTopology *topology; + PROPVARIANT propvar; + HRESULT hr; + LONG ref; + UINT i; + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + + hr = MFCreateMediaType(&output_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_media_type(output_type, video_rgb32_desc, -1); + + callback = create_test_callback(TRUE); + + /* Sinks are always shut down on session shutdown, but never before. + * MF_TOPONODE_NOSHUTDOWN_ON_REMOVE is ignored. */ + + for (i = 0; i < 4; ++i) + { + winetest_push_context("Test %u", i); + + if (!(source = create_media_source(L"test.mp4", L"video/mp4"))) + { + todo_wine /* Gitlab CI Debian runner */ + win_skip("MP4 media source is not supported, skipping tests.\n"); + goto done; + } + + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + if (i & 2) + { + grabber_callback = impl_from_IMFSampleGrabberSinkCallback(create_test_grabber_callback()); + hr = MFCreateSampleGrabberSinkActivate(output_type, &grabber_callback->IMFSampleGrabberSinkCallback_iface, &sink_activate); + ok(hr == S_OK, "Failed to create grabber sink, hr %#lx.\n", hr); + topology = create_test_topology_unk_noshutdown(source, (IUnknown *)sink_activate, NULL, NULL, i & 1); + IMFActivate_Release(sink_activate); + } + else + { + grabber_callback = create_activated_test_grabber_callback(output_type, &stream_sink); + topology = create_test_topology_unk_noshutdown(source, (IUnknown *)stream_sink, NULL, NULL, i & 1); + IMFStreamSink_Release(stream_sink); + } + + hr = IMFMediaSession_SetTopology(session, 0, topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFTopology_Release(topology); + + propvar.vt = VT_EMPTY; + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = wait_media_event(session, callback, MESessionStarted, 5000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaSession_Stop(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event_until_blocking(session, callback, MESessionStopped, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaSession_SetTopology(session, MFSESSION_SETTOPOLOGY_CLEAR_CURRENT, NULL); + 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); + PropVariantClear(&propvar); + todo_wine_if(i == 1) + ok(!grabber_callback->shutdown, "Media sink was shut down.\n"); + + 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); + todo_wine_if(i == 1) + ok(!grabber_callback->shutdown, "Media sink was shut down.\n"); + + hr = IMFMediaSession_Close(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionClosed, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine_if(i == 1) + ok(!grabber_callback->shutdown, "Media sink was shut down.\n"); + + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine_if(i != 1) + ok(grabber_callback->shutdown, "Media sink is not shut down.\n"); + IMFSampleGrabberSinkCallback_Release(&grabber_callback->IMFSampleGrabberSinkCallback_iface); + + hr = IMFMediaSource_Shutdown(source); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + Sleep(20); + ref = IMFMediaSession_Release(session); + todo_wine_if(i != 1) + ok(!ref, "Unexpected refcount %ld.\n", ref); + ref = IMFMediaSource_Release(source); + ok(!ref, "Unexpected refcount %ld.\n", ref); + + winetest_pop_context(); + } + + if (!(source = create_media_source(L"test.mp4", L"video/mp4"))) + { + todo_wine /* Gitlab CI Debian runner */ + win_skip("MP4 media source is not supported, skipping tests.\n"); + goto done; + } + + /* Sinks in queued topologies are not shut down until session shutdown. */ + + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + for (i = 0; i < 2; ++i) + { + grabber_callbacks[i] = create_activated_test_grabber_callback(output_type, &stream_sink); + topology = create_test_topology_unk_noshutdown(source, (IUnknown *)stream_sink, NULL, NULL, 0); + IMFStreamSink_Release(stream_sink); + + hr = IMFMediaSession_SetTopology(session, 0, topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFTopology_Release(topology); + } + + grabber_callbacks[2] = impl_from_IMFSampleGrabberSinkCallback(create_test_grabber_callback()); + hr = MFCreateSampleGrabberSinkActivate(output_type, &grabber_callbacks[2]->IMFSampleGrabberSinkCallback_iface, &sink_activate); + ok(hr == S_OK, "Failed to create grabber sink, hr %#lx.\n", hr); + topology = create_test_topology_unk_noshutdown(source, (IUnknown *)sink_activate, NULL, NULL, 0); + IMFActivate_Release(sink_activate); + + hr = IMFMediaSession_SetTopology(session, 0, topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFTopology_Release(topology); + + propvar.vt = VT_EMPTY; + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = wait_media_event(session, callback, MESessionStarted, 5000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaSession_Close(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionClosed, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < ARRAY_SIZE(grabber_callbacks); ++i) + ok(!grabber_callbacks[i]->shutdown, "Media sink %u was shut down.\n", i); + + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < ARRAY_SIZE(grabber_callbacks); ++i) + { + todo_wine_if(i) + ok(grabber_callbacks[i]->shutdown, "Media sink %u is not shut down.\n", i); + IMFSampleGrabberSinkCallback_Release(&grabber_callbacks[i]->IMFSampleGrabberSinkCallback_iface); + } + + hr = IMFMediaSource_Shutdown(source); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + Sleep(20); + ref = IMFMediaSession_Release(session); + ok(!ref, "Unexpected refcount %ld.\n", ref); + + ref = IMFMediaSource_Release(source); + ok(!ref, "Unexpected refcount %ld.\n", ref); + + /* Unexpected source shutdown does not shut down sinks. + * NOTE: Source re-use is broken in Wine, for more reasons than + * just errors from multiple event subscription. */ + + if (!(source = create_media_source(L"test.mp4", L"video/mp4"))) + { + todo_wine /* Gitlab CI Debian runner */ + win_skip("MP4 media source is not supported, skipping tests.\n"); + goto done; + } + + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + grabber_callback = create_activated_test_grabber_callback(output_type, &stream_sink); + topology = create_test_topology_unk(source, (IUnknown *)stream_sink, NULL, NULL); + IMFStreamSink_Release(stream_sink); + + hr = IMFMediaSession_SetTopology(session, 0, topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFTopology_Release(topology); + + propvar.vt = VT_EMPTY; + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = wait_media_event(session, callback, MESessionStarted, 5000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaSource_Shutdown(source); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!grabber_callback->shutdown, "Media sink was shut down.\n"); + + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(grabber_callback->shutdown, "Media sink is not shut down.\n"); + IMFSampleGrabberSinkCallback_Release(&grabber_callback->IMFSampleGrabberSinkCallback_iface); + + IMFMediaSession_Release(session); + IMFMediaSource_Release(source); + +done: + IMFAsyncCallback_Release(callback); + IMFMediaType_Release(output_type); + + hr = MFShutdown(); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); +} + START_TEST(mf) { init_functions(); @@ -8504,4 +8748,5 @@ START_TEST(mf) test_media_session_source_shutdown(); test_media_session_thinning(); test_media_session_seek(); + test_media_session_sink_shutdown(); }
From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/mf/session.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 8d2ca079634..056855b7077 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -2198,8 +2198,8 @@ static ULONG WINAPI mfsession_Release(IMFMediaSession *iface)
if (!refcount) { - session_clear_queued_topologies(session); - session_clear_presentation(session); + if (SUCCEEDED(session_is_shut_down(session))) + IMFMediaSession_Shutdown(iface); session_clear_command_list(session); if (session->presentation.current_topology) IMFTopology_Release(session->presentation.current_topology); @@ -2477,8 +2477,6 @@ static HRESULT WINAPI mfsession_Shutdown(IMFMediaSession *iface) if (session->quality_manager) IMFQualityManager_Shutdown(session->quality_manager); MFShutdownObject((IUnknown *)session->clock); - IMFPresentationClock_Release(session->clock); - session->clock = NULL; session_clear_presentation(session); session_clear_queued_topologies(session); session_submit_simple_command(session, SESSION_CMD_SHUTDOWN);
From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/mf/session.c | 58 +++++++++++++++++++++++++--------------------- dlls/mf/tests/mf.c | 11 --------- 2 files changed, 31 insertions(+), 38 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 056855b7077..bd35cb9ad8f 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -277,6 +277,7 @@ struct media_session BOOL thin_committed; } presentation; struct list topologies; + struct list removed_topologies; struct list commands; enum session_state state; enum command_state command_state; @@ -522,8 +523,7 @@ static void session_clear_queued_topologies(struct media_session *session) LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &session->topologies, struct queued_topology, entry) { list_remove(&ptr->entry); - IMFTopology_Release(ptr->topology); - free(ptr); + list_add_tail(&session->removed_topologies, &ptr->entry); } }
@@ -819,21 +819,16 @@ static void release_topo_node(struct topo_node *node) free(node); }
-static void session_shutdown_current_topology(struct media_session *session) +static void topology_shutdown(IMFTopology *topology) { - unsigned int shutdown, force_shutdown; MF_TOPOLOGY_TYPE node_type; IMFStreamSink *stream_sink; - IMFTopology *topology; IMFTopologyNode *node; IMFActivate *activate; IMFMediaSink *sink; WORD idx = 0; HRESULT hr;
- topology = session->presentation.current_topology; - force_shutdown = session->state == SESSION_STATE_SHUT_DOWN; - /* FIXME: should handle async MFTs, but these are not supported by the rest of the pipeline currently. */
while (SUCCEEDED(IMFTopology_GetNode(topology, idx++, &node))) @@ -841,28 +836,24 @@ static void session_shutdown_current_topology(struct media_session *session) if (SUCCEEDED(IMFTopologyNode_GetNodeType(node, &node_type)) && node_type == MF_TOPOLOGY_OUTPUT_NODE) { - shutdown = 1; - IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, &shutdown); + /* MF_TOPONODE_NOSHUTDOWN_ON_REMOVE is ignored, at least for sinks. */
- if (force_shutdown || shutdown) + if (SUCCEEDED(IMFTopologyNode_GetUnknown(node, &_MF_TOPONODE_IMFActivate, &IID_IMFActivate, + (void **)&activate))) { - if (SUCCEEDED(IMFTopologyNode_GetUnknown(node, &_MF_TOPONODE_IMFActivate, &IID_IMFActivate, - (void **)&activate))) + if (FAILED(hr = IMFActivate_ShutdownObject(activate))) + WARN("Failed to shut down activation object for the sink, hr %#lx.\n", hr); + IMFActivate_Release(activate); + } + if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink))) + { + if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink))) { - if (FAILED(hr = IMFActivate_ShutdownObject(activate))) - WARN("Failed to shut down activation object for the sink, hr %#lx.\n", hr); - IMFActivate_Release(activate); + IMFMediaSink_Shutdown(sink); + IMFMediaSink_Release(sink); } - else if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink))) - { - if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink))) - { - IMFMediaSink_Shutdown(sink); - IMFMediaSink_Release(sink); - }
- IMFStreamSink_Release(stream_sink); - } + IMFStreamSink_Release(stream_sink); } }
@@ -870,6 +861,19 @@ static void session_shutdown_current_topology(struct media_session *session) } }
+static void session_clear_removed_topologies(struct media_session *session) +{ + struct queued_topology *ptr, *next; + + LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &session->removed_topologies, struct queued_topology, entry) + { + list_remove(&ptr->entry); + topology_shutdown(ptr->topology); + IMFTopology_Release(ptr->topology); + free(ptr); + } +} + static void session_clear_command_list(struct media_session *session) { struct session_op *op, *op2; @@ -891,8 +895,6 @@ static void session_clear_presentation(struct media_session *session) struct media_sink *sink, *sink2; struct topo_node *node, *node2;
- session_shutdown_current_topology(session); - IMFTopology_Clear(session->presentation.current_topology); session->presentation.topo_status = MF_TOPOSTATUS_INVALID; session->presentation.flags = 0; @@ -2479,6 +2481,7 @@ static HRESULT WINAPI mfsession_Shutdown(IMFMediaSession *iface) MFShutdownObject((IUnknown *)session->clock); session_clear_presentation(session); session_clear_queued_topologies(session); + session_clear_removed_topologies(session); session_submit_simple_command(session, SESSION_CMD_SHUTDOWN); } LeaveCriticalSection(&session->cs); @@ -4865,6 +4868,7 @@ HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **ses object->sink_finalizer_callback.lpVtbl = &session_sink_finalizer_callback_vtbl; object->refcount = 1; list_init(&object->topologies); + list_init(&object->removed_topologies); list_init(&object->commands); list_init(&object->presentation.sources); list_init(&object->presentation.sinks); diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index cd02890a40c..9dcd83f7c4c 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -4510,7 +4510,6 @@ static void test_sample_grabber_orientation(GUID subtype)
hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(grabber_callback->shutdown, "Media sink is not shut down.\n"); hr = IMFMediaSource_Shutdown(source); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -7140,7 +7139,6 @@ static void test_media_session_Start(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(grabber_callback->shutdown, "Media sink is not shut down.\n");
propvar.vt = VT_I8; @@ -7223,7 +7221,6 @@ static void test_media_session_Start(void) ok(!grabber_callback->shutdown, "Media sink was shut down.\n"); hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(grabber_callback->shutdown, "Media sink is not shut down.\n"); hr = IMFMediaSource_Shutdown(source); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -7670,7 +7667,6 @@ static void test_media_session_Close(void)
hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(grabber_callback->shutdown, "Media sink is not shut down.\n");
IMFPresentationClock_Release(presentation_clock); @@ -7814,7 +7810,6 @@ static void test_media_session_thinning(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(grabber_callback->shutdown, "Media sink is not shut down.\n"); hr = IMFMediaSource_Shutdown(source); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -8558,26 +8553,22 @@ static void test_media_session_sink_shutdown(void) hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); PropVariantClear(&propvar); - todo_wine_if(i == 1) ok(!grabber_callback->shutdown, "Media sink was shut down.\n");
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); - todo_wine_if(i == 1) ok(!grabber_callback->shutdown, "Media sink was shut down.\n");
hr = IMFMediaSession_Close(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = wait_media_event(session, callback, MESessionClosed, 1000, &propvar); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine_if(i == 1) ok(!grabber_callback->shutdown, "Media sink was shut down.\n");
hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine_if(i != 1) ok(grabber_callback->shutdown, "Media sink is not shut down.\n"); IMFSampleGrabberSinkCallback_Release(&grabber_callback->IMFSampleGrabberSinkCallback_iface);
@@ -8586,7 +8577,6 @@ static void test_media_session_sink_shutdown(void)
Sleep(20); ref = IMFMediaSession_Release(session); - todo_wine_if(i != 1) ok(!ref, "Unexpected refcount %ld.\n", ref); ref = IMFMediaSource_Release(source); ok(!ref, "Unexpected refcount %ld.\n", ref); @@ -8645,7 +8635,6 @@ static void test_media_session_sink_shutdown(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); for (i = 0; i < ARRAY_SIZE(grabber_callbacks); ++i) { - todo_wine_if(i) ok(grabber_callbacks[i]->shutdown, "Media sink %u is not shut down.\n", i); IMFSampleGrabberSinkCallback_Release(&grabber_callbacks[i]->IMFSampleGrabberSinkCallback_iface); }