mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-30 12:49:40 +00:00
bin: add "deep-element-added" and "deep-element-removed" signals
This means applications and bin sub-classes can easily track when a new child element is added to the pipeline sub-hierarchy or removed. Currently doesn't signal deep added/removed for elements inside a bin if a bin is added/removed. https://bugzilla.gnome.org/show_bug.cgi?id=578933
This commit is contained in:
parent
edb27a8ec2
commit
81dec8cc4d
3 changed files with 179 additions and 1 deletions
89
gst/gstbin.c
89
gst/gstbin.c
|
@ -225,6 +225,10 @@ static void bin_do_eos (GstBin * bin);
|
|||
|
||||
static gboolean gst_bin_add_func (GstBin * bin, GstElement * element);
|
||||
static gboolean gst_bin_remove_func (GstBin * bin, GstElement * element);
|
||||
static void gst_bin_deep_element_added_func (GstBin * bin, GstBin * sub_bin,
|
||||
GstElement * element);
|
||||
static void gst_bin_deep_element_removed_func (GstBin * bin, GstBin * sub_bin,
|
||||
GstElement * element);
|
||||
static void gst_bin_update_context (GstBin * bin, GstContext * context);
|
||||
static void gst_bin_update_context_unlocked (GstBin * bin,
|
||||
GstContext * context);
|
||||
|
@ -260,6 +264,8 @@ enum
|
|||
ELEMENT_ADDED,
|
||||
ELEMENT_REMOVED,
|
||||
DO_LATENCY,
|
||||
DEEP_ELEMENT_ADDED,
|
||||
DEEP_ELEMENT_REMOVED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
|
@ -400,6 +406,36 @@ gst_bin_class_init (GstBinClass * klass)
|
|||
g_signal_new ("element-removed", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_removed), NULL,
|
||||
NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
|
||||
/**
|
||||
* GstBin::deep-element-added:
|
||||
* @bin: the #GstBin
|
||||
* @sub_bin: the #GstBin the element was added to
|
||||
* @element: the #GstElement that was added to @sub_bin
|
||||
*
|
||||
* Will be emitted after the element was added to sub_bin.
|
||||
*
|
||||
* Since: 1.10
|
||||
*/
|
||||
gst_bin_signals[DEEP_ELEMENT_ADDED] =
|
||||
g_signal_new ("deep-element-added", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, deep_element_added),
|
||||
NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, GST_TYPE_BIN,
|
||||
GST_TYPE_ELEMENT);
|
||||
/**
|
||||
* GstBin::deep-element-removed:
|
||||
* @bin: the #GstBin
|
||||
* @sub_bin: the #GstBin the element was removed from
|
||||
* @element: the #GstElement that was removed from @sub_bin
|
||||
*
|
||||
* Will be emitted after the element was removed from sub_bin.
|
||||
*
|
||||
* Since: 1.10
|
||||
*/
|
||||
gst_bin_signals[DEEP_ELEMENT_REMOVED] =
|
||||
g_signal_new ("deep-element-removed", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, deep_element_removed),
|
||||
NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, GST_TYPE_BIN,
|
||||
GST_TYPE_ELEMENT);
|
||||
/**
|
||||
* GstBin::do-latency:
|
||||
* @bin: the #GstBin
|
||||
|
@ -467,6 +503,9 @@ gst_bin_class_init (GstBinClass * klass)
|
|||
klass->remove_element = GST_DEBUG_FUNCPTR (gst_bin_remove_func);
|
||||
klass->handle_message = GST_DEBUG_FUNCPTR (gst_bin_handle_message_func);
|
||||
|
||||
klass->deep_element_added = gst_bin_deep_element_added_func;
|
||||
klass->deep_element_removed = gst_bin_deep_element_removed_func;
|
||||
|
||||
klass->do_latency = GST_DEBUG_FUNCPTR (gst_bin_do_latency_func);
|
||||
}
|
||||
|
||||
|
@ -1288,6 +1327,8 @@ no_state_recalc:
|
|||
gst_child_proxy_child_added ((GstChildProxy *) bin, (GObject *) element,
|
||||
elem_name);
|
||||
|
||||
g_signal_emit (bin, gst_bin_signals[DEEP_ELEMENT_ADDED], 0, bin, element);
|
||||
|
||||
g_free (elem_name);
|
||||
|
||||
return TRUE;
|
||||
|
@ -1317,6 +1358,52 @@ had_parent:
|
|||
}
|
||||
}
|
||||
|
||||
/* signal vfunc, will be called when a new element was added */
|
||||
static void
|
||||
gst_bin_deep_element_added_func (GstBin * bin, GstBin * sub_bin,
|
||||
GstElement * child)
|
||||
{
|
||||
GstBin *parent_bin;
|
||||
|
||||
parent_bin = (GstBin *) gst_object_get_parent (GST_OBJECT_CAST (bin));
|
||||
if (parent_bin == NULL) {
|
||||
GST_LOG_OBJECT (bin, "no parent, reached top-level");
|
||||
return;
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (parent_bin, "emitting deep-element-added for element "
|
||||
"%" GST_PTR_FORMAT " which has just been added to %" GST_PTR_FORMAT,
|
||||
sub_bin, child);
|
||||
|
||||
g_signal_emit (parent_bin, gst_bin_signals[DEEP_ELEMENT_ADDED], 0, sub_bin,
|
||||
child);
|
||||
|
||||
gst_object_unref (parent_bin);
|
||||
}
|
||||
|
||||
/* signal vfunc, will be called when an element was removed */
|
||||
static void
|
||||
gst_bin_deep_element_removed_func (GstBin * bin, GstBin * sub_bin,
|
||||
GstElement * child)
|
||||
{
|
||||
GstBin *parent_bin;
|
||||
|
||||
parent_bin = (GstBin *) gst_object_get_parent (GST_OBJECT_CAST (bin));
|
||||
if (parent_bin == NULL) {
|
||||
GST_LOG_OBJECT (bin, "no parent, reached top-level");
|
||||
return;
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (parent_bin, "emitting deep-element-removed for element "
|
||||
"%" GST_PTR_FORMAT " which has just been removed from %" GST_PTR_FORMAT,
|
||||
sub_bin, child);
|
||||
|
||||
g_signal_emit (parent_bin, gst_bin_signals[DEEP_ELEMENT_REMOVED], 0, sub_bin,
|
||||
child);
|
||||
|
||||
gst_object_unref (parent_bin);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_bin_add:
|
||||
* @bin: a #GstBin
|
||||
|
@ -1623,6 +1710,8 @@ no_state_recalc:
|
|||
gst_child_proxy_child_removed ((GstChildProxy *) bin, (GObject *) element,
|
||||
elem_name);
|
||||
|
||||
g_signal_emit (bin, gst_bin_signals[DEEP_ELEMENT_REMOVED], 0, bin, element);
|
||||
|
||||
g_free (elem_name);
|
||||
/* element is really out of our control now */
|
||||
gst_object_unref (element);
|
||||
|
|
13
gst/gstbin.h
13
gst/gstbin.h
|
@ -147,6 +147,12 @@ struct _GstBin {
|
|||
* The @handle_message method can be overridden to implement custom
|
||||
* message handling. @handle_message takes ownership of the message, just like
|
||||
* #gst_element_post_message.
|
||||
*
|
||||
* The @element_added_deep vfunc will be called when a new element has been
|
||||
* added to any bin inside this bin, so it will also be called if a new child
|
||||
* was added to a sub-bin of this bin. #GstBin implementations that override
|
||||
* this message should chain up to the parent class implementation so the
|
||||
* element-added-deep signal is emitted on all parents.
|
||||
*/
|
||||
struct _GstBinClass {
|
||||
GstElementClass parent_class;
|
||||
|
@ -169,8 +175,13 @@ struct _GstBinClass {
|
|||
/* signal */
|
||||
gboolean (*do_latency) (GstBin *bin);
|
||||
|
||||
/*< public >*/
|
||||
/* signal */
|
||||
void (*deep_element_added) (GstBin *bin, GstBin *sub_bin, GstElement *child);
|
||||
void (*deep_element_removed) (GstBin *bin, GstBin *sub_bin, GstElement *child);
|
||||
|
||||
/*< private >*/
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
gpointer _gst_reserved[GST_PADDING-2];
|
||||
};
|
||||
|
||||
GType gst_bin_get_type (void);
|
||||
|
|
|
@ -1545,7 +1545,84 @@ GST_START_TEST (test_duration_unknown_overrides)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
static gboolean
|
||||
element_in_list (GList ** list, GstElement * element)
|
||||
{
|
||||
GList *l = g_list_find (*list, element);
|
||||
|
||||
if (l == NULL)
|
||||
return FALSE;
|
||||
|
||||
*list = g_list_delete_link (*list, l);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define element_was_added(e) element_in_list(&added,e)
|
||||
#define element_was_removed(e) element_in_list(&removed,e)
|
||||
|
||||
static void
|
||||
add_cb (GstBin * pipeline, GstBin * bin, GstElement * element, GList ** list)
|
||||
{
|
||||
fail_unless (GST_OBJECT_PARENT (element) == GST_OBJECT_CAST (bin));
|
||||
|
||||
*list = g_list_prepend (*list, element);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_cb (GstBin * pipeline, GstBin * bin, GstElement * element, GList ** list)
|
||||
{
|
||||
fail_unless (GST_OBJECT_PARENT (element) == NULL);
|
||||
|
||||
*list = g_list_prepend (*list, element);
|
||||
}
|
||||
|
||||
GST_START_TEST (test_deep_added_removed)
|
||||
{
|
||||
GstElement *pipe, *e, *bin0, *bin1;
|
||||
gulong id_removed, id_added;
|
||||
GList *removed = NULL;
|
||||
GList *added = NULL;
|
||||
|
||||
pipe = gst_pipeline_new (NULL);
|
||||
|
||||
id_added = g_signal_connect (pipe, "deep-element-added",
|
||||
G_CALLBACK (add_cb), &added);
|
||||
id_removed = g_signal_connect (pipe, "deep-element-removed",
|
||||
G_CALLBACK (remove_cb), &removed);
|
||||
|
||||
/* simple add/remove */
|
||||
e = gst_element_factory_make ("identity", NULL);
|
||||
gst_bin_add (GST_BIN (pipe), e);
|
||||
fail_unless (element_was_added (e));
|
||||
gst_bin_remove (GST_BIN (pipe), e);
|
||||
fail_unless (element_was_removed (e));
|
||||
|
||||
/* let's try with a deeper hierarchy */
|
||||
bin0 = gst_bin_new (NULL);
|
||||
gst_bin_add (GST_BIN (pipe), bin0);
|
||||
bin1 = gst_bin_new (NULL);
|
||||
gst_bin_add (GST_BIN (bin0), bin1);
|
||||
e = gst_element_factory_make ("identity", NULL);
|
||||
gst_bin_add (GST_BIN (bin1), e);
|
||||
fail_unless (element_was_added (bin0));
|
||||
fail_unless (element_was_added (bin1));
|
||||
fail_unless (element_was_added (e));
|
||||
fail_unless (added == NULL);
|
||||
fail_unless (removed == NULL);
|
||||
|
||||
gst_bin_remove (GST_BIN (bin1), e);
|
||||
fail_unless (element_was_removed (e));
|
||||
fail_unless (added == NULL);
|
||||
fail_unless (removed == NULL);
|
||||
|
||||
/* disconnect signals, unref will trigger remove callbacks otherwise */
|
||||
g_signal_handler_disconnect (pipe, id_added);
|
||||
g_signal_handler_disconnect (pipe, id_removed);
|
||||
|
||||
gst_object_unref (pipe);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
gst_bin_suite (void)
|
||||
|
@ -1576,6 +1653,7 @@ gst_bin_suite (void)
|
|||
tcase_add_test (tc_chain, test_state_change_skip);
|
||||
tcase_add_test (tc_chain, test_duration_is_max);
|
||||
tcase_add_test (tc_chain, test_duration_unknown_overrides);
|
||||
tcase_add_test (tc_chain, test_deep_added_removed);
|
||||
|
||||
/* fails on OSX build bot for some reason, and is a bit silly anyway */
|
||||
if (0)
|
||||
|
|
Loading…
Reference in a new issue