mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-18 14:26:43 +00:00
bin: fix refcount when removing elements during state change
When an element is removed from a bin because it caused a state change error, don't unref the child twice. Add some more debug info. Add a unit test for this error. Fixes #615756
This commit is contained in:
parent
88b4a704f3
commit
67ab660b19
2 changed files with 63 additions and 3 deletions
11
gst/gstbin.c
11
gst/gstbin.c
|
@ -2446,17 +2446,22 @@ restart:
|
||||||
/* Only fail if the child is still inside
|
/* Only fail if the child is still inside
|
||||||
* this bin. It might've been removed already
|
* this bin. It might've been removed already
|
||||||
* because of the error by the bin subclass
|
* because of the error by the bin subclass
|
||||||
* to ignore the error.
|
* to ignore the error. */
|
||||||
*/
|
|
||||||
parent = gst_object_get_parent (GST_OBJECT_CAST (child));
|
parent = gst_object_get_parent (GST_OBJECT_CAST (child));
|
||||||
if (parent == GST_OBJECT_CAST (element)) {
|
if (parent == GST_OBJECT_CAST (element)) {
|
||||||
|
/* element is still in bin, really error now */
|
||||||
gst_object_unref (child);
|
gst_object_unref (child);
|
||||||
gst_object_unref (parent);
|
gst_object_unref (parent);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
/* child removed from bin, let the resync code redo the state
|
||||||
|
* change */
|
||||||
|
GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
|
||||||
|
"child '%s' was removed from the bin",
|
||||||
|
GST_ELEMENT_NAME (child));
|
||||||
|
|
||||||
if (parent)
|
if (parent)
|
||||||
gst_object_unref (parent);
|
gst_object_unref (parent);
|
||||||
gst_object_unref (child);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -971,6 +971,60 @@ GST_START_TEST (test_link_structure_change)
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
||||||
|
static GstBusSyncReply
|
||||||
|
sync_handler_remove_sink (GstBus * bus, GstMessage * message, gpointer data)
|
||||||
|
{
|
||||||
|
if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR) {
|
||||||
|
GstElement *child;
|
||||||
|
|
||||||
|
child = gst_bin_get_by_name (GST_BIN (data), "fakesink");
|
||||||
|
fail_unless (child != NULL, "Could not find fakesink");
|
||||||
|
|
||||||
|
gst_bin_remove (GST_BIN (data), child);
|
||||||
|
gst_object_unref (child);
|
||||||
|
}
|
||||||
|
return GST_BUS_PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_START_TEST (test_state_failure_remove)
|
||||||
|
{
|
||||||
|
GstElement *src, *sink, *pipeline;
|
||||||
|
GstBus *bus;
|
||||||
|
GstStateChangeReturn ret;
|
||||||
|
|
||||||
|
pipeline = gst_pipeline_new (NULL);
|
||||||
|
fail_unless (pipeline != NULL, "Could not create pipeline");
|
||||||
|
|
||||||
|
src = gst_element_factory_make ("fakesrc", "fakesrc");
|
||||||
|
fail_unless (src != NULL, "Could not create fakesrc");
|
||||||
|
|
||||||
|
sink = gst_element_factory_make ("fakesink", "fakesink");
|
||||||
|
fail_unless (sink != NULL, "Could not create fakesink");
|
||||||
|
|
||||||
|
g_object_set (sink, "state-error", 1, NULL);
|
||||||
|
|
||||||
|
gst_bin_add (GST_BIN (pipeline), src);
|
||||||
|
gst_bin_add (GST_BIN (pipeline), sink);
|
||||||
|
|
||||||
|
gst_element_link (src, sink);
|
||||||
|
|
||||||
|
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
|
||||||
|
fail_unless (bus != NULL, "Could not get bus");
|
||||||
|
|
||||||
|
gst_bus_set_sync_handler (bus, sync_handler_remove_sink, pipeline);
|
||||||
|
|
||||||
|
ret = gst_element_set_state (pipeline, GST_STATE_READY);
|
||||||
|
fail_unless (ret == GST_STATE_CHANGE_SUCCESS,
|
||||||
|
"did not get state change success");
|
||||||
|
|
||||||
|
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||||
|
|
||||||
|
gst_object_unref (bus);
|
||||||
|
gst_object_unref (pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
static Suite *
|
static Suite *
|
||||||
gst_bin_suite (void)
|
gst_bin_suite (void)
|
||||||
{
|
{
|
||||||
|
@ -992,6 +1046,7 @@ gst_bin_suite (void)
|
||||||
tcase_add_test (tc_chain, test_add_self);
|
tcase_add_test (tc_chain, test_add_self);
|
||||||
tcase_add_test (tc_chain, test_iterate_sorted);
|
tcase_add_test (tc_chain, test_iterate_sorted);
|
||||||
tcase_add_test (tc_chain, test_link_structure_change);
|
tcase_add_test (tc_chain, test_link_structure_change);
|
||||||
|
tcase_add_test (tc_chain, test_state_failure_remove);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue