{
GstObject *parent;
gboolean res;
+ GstPadMode old, new;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
GST_OBJECT_LOCK (pad);
+
+ old = GST_PAD_MODE (pad);
+ new = active ? mode : GST_PAD_MODE_NONE;
+ if (old == new)
+ goto was_ok;
+
ACQUIRE_PARENT (pad, parent, no_parent);
+
GST_OBJECT_UNLOCK (pad);
res = activate_mode_internal (pad, parent, mode, active);
return res;
+was_ok:
+ {
+ GST_OBJECT_UNLOCK (pad);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "already %s in %s mode",
+ active ? "activated" : "deactivated", gst_pad_mode_get_name (mode));
+ return TRUE;
+ }
no_parent:
{
GST_WARNING_OBJECT (pad, "no parent");
GST_END_TEST;
static gboolean thread_running;
+
static gpointer
send_query_to_pad_func (GstPad * pad)
{
GST_END_TEST;
+GST_START_TEST (test_deactivate_already_deactive_with_no_parent)
+{
+ /* This simulates the behavior where a ghostpad is released while
+ * deactivating (for instance because of a state change).
+ * gst_pad_activate_mode() may be be called from
+ * gst_ghost_pad_internal_activate_push_default() on a pad that is already
+ * deactivate and unparented. The call chain is really like somethink like
+ * this:
+ * gst_pad_activate_mode(ghostpad)
+ * -> ...
+ * -> gst_pad_activate_mode(proxypad)
+ * -> ...
+ * -> gst_pad_activate_mode(ghostpad)
+ */
+ GstElement *bin = gst_bin_new ("testbin");
+ GstPad *pad = gst_ghost_pad_new_no_target ("src", GST_PAD_SRC);
+ gst_object_ref (pad);
+
+ /* We need to add/remove pad because that will update the pad's flags */
+ fail_unless (gst_element_add_pad (bin, pad));
+ fail_unless (gst_element_remove_pad (bin, pad));
+
+ /* Setting a pad that's already deactive to deactive should not fail. */
+ fail_if (gst_pad_is_active (pad));
+ fail_unless (gst_pad_activate_mode (pad, GST_PAD_MODE_PUSH, FALSE));
+
+ gst_object_unref (bin);
+ gst_object_unref (pad);
+}
+
+GST_END_TEST;
+
static Suite *
gst_ghost_pad_suite (void)
{
tcase_add_test (tc_chain, test_activate_sink_and_src);
tcase_add_test (tc_chain, test_activate_src_pull_mode);
tcase_add_test (tc_chain, test_activate_sink_switch_mode);
+ tcase_add_test (tc_chain, test_deactivate_already_deactive_with_no_parent);
tcase_add_test (tc_chain, test_stress_upstream_queries_while_tearing_down);
return s;