From: Mathieu Duponchelle Date: Tue, 24 Jun 2014 11:44:13 +0000 (+0200) Subject: gnl: Add the srcpad directly to GnlObject X-Git-Tag: 1.19.3~493^2~1503 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4cb834fa2196cb241ab6c8a0e737046b1ff7d03d;p=platform%2Fupstream%2Fgstreamer.git gnl: Add the srcpad directly to GnlObject Starting from now we will not claim that we support GnlObject that have several source pads as this is 1- Not true at all; 2- the design of priorities in the GnlComposition tree does not allow that; 3- Not very useful in most of the cases and it complexifies quite a lot the code in the composition. Conflicts: configure.ac tests/check/Makefile.am --- diff --git a/gnl/gnlcomposition.c b/gnl/gnlcomposition.c index d9a0877..179bf29 100644 --- a/gnl/gnlcomposition.c +++ b/gnl/gnlcomposition.c @@ -34,7 +34,7 @@ static GstStaticPadTemplate gnl_composition_src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, - GST_PAD_SOMETIMES, + GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); GST_DEBUG_CATEGORY_STATIC (gnlcomposition_debug); @@ -96,7 +96,6 @@ struct _GnlCompositionPrivate gboolean flushing; /* source top-level ghostpad, probe and entry */ - GstPad *ghostpad; gulong ghosteventprobe; GnlCompositionEntry *toplevelentry; @@ -120,9 +119,6 @@ struct _GnlCompositionPrivate GstClockTime segment_start; GstClockTime segment_stop; - /* pending child seek */ - GstEvent *childseek; - /* Seek segment handler */ GstSegment *segment; GstSegment *outside_segment; @@ -130,9 +126,6 @@ struct _GnlCompositionPrivate /* Next running base_time to set on outgoing segment */ guint64 next_base_time; - /* number of pads we are waiting to appear so be can do proper linking */ - guint waitingpads; - /* OUR sync_handler on the child_bus We are called before gnl_object_sync_handler @@ -178,10 +171,9 @@ gnl_composition_remove_object (GstBin * bin, GstElement * element); static GstStateChangeReturn gnl_composition_change_state (GstElement * element, GstStateChange transition); -static GstPad *get_src_pad (GstElement * element); static GstPadProbeReturn pad_blocked (GstPad * pad, GstPadProbeInfo * info, GnlComposition * comp); -static inline void gnl_composition_remove_ghostpad (GnlComposition * comp); +static inline void gnl_composition_reset_target_pad (GnlComposition * comp); static gboolean seek_handling (GnlComposition * comp, gboolean initial, gboolean update); @@ -191,12 +183,14 @@ static GstClockTime get_current_position (GnlComposition * comp); static gboolean update_pipeline (GnlComposition * comp, GstClockTime currenttime, gboolean initial, gboolean modify); -static void no_more_pads_object_cb (GstElement * element, - GnlComposition * comp); static gboolean gnl_composition_commit_func (GnlObject * object, gboolean recurse); static void update_start_stop_duration (GnlComposition * comp); +static gboolean +gnl_composition_event_handler (GstPad * ghostpad, GstObject * parent, + GstEvent * event); + /* COMP_REAL_START: actual position to start current playback at. */ #define COMP_REAL_START(comp) \ @@ -263,11 +257,6 @@ struct _GnlCompositionEntry GnlObject *object; GnlComposition *comp; - /* handler id for 'no-more-pads' signal */ - gulong nomorepadshandler; - gulong padaddedhandler; - gulong padremovedhandler; - /* handler id for block probe */ gulong probeid; gulong dataprobeid; @@ -368,23 +357,15 @@ hash_value_destroy (GnlCompositionEntry * entry) GstPad *srcpad; GstElement *element = GST_ELEMENT (entry->object); - g_signal_handler_disconnect (entry->object, entry->padremovedhandler); - g_signal_handler_disconnect (entry->object, entry->padaddedhandler); - - if (entry->nomorepadshandler) - g_signal_handler_disconnect (entry->object, entry->nomorepadshandler); - - if ((srcpad = get_src_pad (element))) { - if (entry->probeid) { - gst_pad_remove_probe (srcpad, entry->probeid); - entry->probeid = 0; - } + srcpad = GNL_OBJECT_SRC (element); + if (entry->probeid) { + gst_pad_remove_probe (srcpad, entry->probeid); + entry->probeid = 0; + } - if (entry->dataprobeid) { - gst_pad_remove_probe (srcpad, entry->dataprobeid); - entry->dataprobeid = 0; - } - gst_object_unref (srcpad); + if (entry->dataprobeid) { + gst_pad_remove_probe (srcpad, entry->dataprobeid); + entry->dataprobeid = 0; } g_slice_free (GnlCompositionEntry, entry); @@ -410,8 +391,6 @@ gnl_composition_init (GnlComposition * comp) priv->segment = gst_segment_new (); priv->outside_segment = gst_segment_new (); - priv->waitingpads = 0; - priv->reset_time = FALSE; priv->objects_hash = g_hash_table_new_full @@ -423,6 +402,10 @@ gnl_composition_init (GnlComposition * comp) comp->priv = priv; gnl_composition_reset (comp); + + priv->gnl_event_pad_func = GST_PAD_EVENTFUNC (GNL_OBJECT_SRC (comp)); + gst_pad_set_event_function (GNL_OBJECT_SRC (comp), + GST_DEBUG_FUNCPTR (gnl_composition_event_handler)); } static void @@ -436,14 +419,6 @@ gnl_composition_dispose (GObject * object) priv->dispose_has_run = TRUE; - if (priv->ghostpad) - gnl_composition_remove_ghostpad (comp); - - if (priv->childseek) { - gst_event_unref (priv->childseek); - priv->childseek = NULL; - } - if (priv->current) { g_node_destroy (priv->current); priv->current = NULL; @@ -453,6 +428,7 @@ gnl_composition_dispose (GObject * object) g_list_free (priv->expandables); priv->expandables = NULL; } + gnl_composition_reset_target_pad (comp); G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -514,32 +490,10 @@ gnl_composition_get_property (GObject * object, guint prop_id, } } -static void -wait_no_more_pads (GnlComposition * comp, gpointer object, - GnlCompositionEntry * entry, gboolean wait) -{ - if (wait) { - GST_INFO_OBJECT (object, "no existing pad, connecting to 'no-more-pads'"); - entry->nomorepadshandler = g_signal_connect - (G_OBJECT (object), "no-more-pads", - G_CALLBACK (no_more_pads_object_cb), comp); - comp->priv->waitingpads++; - } else { - GST_INFO_OBJECT (object, "disconnecting from 'no-more-pads'"); - g_signal_handler_disconnect (object, entry->nomorepadshandler); - entry->nomorepadshandler = 0; - comp->priv->waitingpads--; - } - - GST_INFO_OBJECT (comp, "the number of waiting pads is now %d", - comp->priv->waitingpads); -} - /* signal_duration_change * Creates a new GST_MESSAGE_DURATION_CHANGED with the currently configured * composition duration and sends that on the bus. */ - static inline void signal_duration_change (GnlComposition * comp) { @@ -557,13 +511,10 @@ unblock_child_pads (GValue * item, GValue * ret G_GNUC_UNUSED, GST_DEBUG_OBJECT (child, "unblocking pads"); - pad = get_src_pad (child); - if (pad) { - if (entry->probeid) { - gst_pad_remove_probe (pad, entry->probeid); - entry->probeid = 0; - } - gst_object_unref (pad); + pad = GNL_OBJECT_SRC (child); + if (entry->probeid) { + gst_pad_remove_probe (pad, entry->probeid); + entry->probeid = 0; } return TRUE; } @@ -592,13 +543,20 @@ reset_child (GValue * item, GValue * ret G_GNUC_UNUSED, gpointer user_data) GnlCompositionEntry *entry; GstElement *child = g_value_get_object (item); GnlComposition *comp = GNL_COMPOSITION (user_data); + GnlObject *object; + GstPad *srcpad, *peerpad; GST_DEBUG_OBJECT (child, "unlocking state"); gst_element_set_locked_state (child, FALSE); entry = COMP_ENTRY (comp, child); - if (entry->nomorepadshandler) - wait_no_more_pads (comp, child, entry, FALSE); + object = entry->object; + srcpad = object->srcpad; + peerpad = gst_pad_get_peer (srcpad); + if (peerpad) { + gst_pad_unlink (srcpad, peerpad); + gst_object_unref (peerpad); + } return TRUE; } @@ -651,13 +609,7 @@ gnl_composition_reset (GnlComposition * comp) priv->stackvalid = FALSE; - if (priv->ghostpad) - gnl_composition_remove_ghostpad (comp); - - if (priv->childseek) { - gst_event_unref (priv->childseek); - priv->childseek = NULL; - } + gnl_composition_reset_target_pad (comp); reset_children (comp); @@ -992,27 +944,26 @@ get_current_position (GnlComposition * comp) gboolean res; gint64 value = GST_CLOCK_TIME_NONE; + GstPad *peer = gst_pad_get_peer (GNL_OBJECT (comp)->srcpad); + /* 1. Try querying position downstream */ - if (priv->ghostpad) { - GstPad *peer = gst_pad_get_peer (priv->ghostpad); - if (peer) { - res = gst_pad_query_position (peer, GST_FORMAT_TIME, &value); - gst_object_unref (peer); + if (peer) { + res = gst_pad_query_position (peer, GST_FORMAT_TIME, &value); + gst_object_unref (peer); - if (res) { - GST_LOG_OBJECT (comp, - "Successfully got downstream position %" GST_TIME_FORMAT, - GST_TIME_ARGS ((guint64) value)); - goto beach; - } + if (res) { + GST_LOG_OBJECT (comp, + "Successfully got downstream position %" GST_TIME_FORMAT, + GST_TIME_ARGS ((guint64) value)); + goto beach; } + } - GST_DEBUG_OBJECT (comp, "Downstream position query failed"); + GST_DEBUG_OBJECT (comp, "Downstream position query failed"); - /* resetting format/value */ - value = GST_CLOCK_TIME_NONE; - } + /* resetting format/value */ + value = GST_CLOCK_TIME_NONE; /* 2. If downstream fails , try within the current stack */ if (!priv->current) { @@ -1022,14 +973,11 @@ get_current_position (GnlComposition * comp) obj = (GnlObject *) priv->current->data; - if (!(pad = get_src_pad ((GstElement *) obj))) - goto beach; - + pad = GNL_OBJECT_SRC (obj); res = gst_pad_query_position (pad, GST_FORMAT_TIME, &value); if (G_UNLIKELY (res == FALSE)) { - GST_WARNING_OBJECT (comp, - "query failed or returned a format different from TIME"); + GST_WARNING_OBJECT (comp, "query position failed"); value = GST_CLOCK_TIME_NONE; } else { GST_LOG_OBJECT (comp, "Query returned %" GST_TIME_FORMAT, @@ -1098,7 +1046,7 @@ seek_handling (GnlComposition * comp, gboolean initial, gboolean update) return TRUE; } -static void +static gboolean handle_seek_event (GnlComposition * comp, GstEvent * event) { gdouble rate; @@ -1122,6 +1070,14 @@ handle_seek_event (GnlComposition * comp, GstEvent * event) GST_DEBUG_OBJECT (comp, "Segment now has flags:%d", priv->segment->flags); + if (priv->segment->start >= GNL_OBJECT_STOP (comp)) { + GST_INFO_OBJECT (comp, + "Start %" GST_TIME_FORMAT " > comp->stop: %" GST_TIME_FORMAT + " Not seeking", GST_TIME_ARGS (priv->segment->start), + GST_TIME_ARGS (GNL_OBJECT_STOP (comp))); + return FALSE; + } + /* crop the segment start/stop values */ /* Only crop segment start value if we don't have a default object */ if (priv->expandables == NULL) @@ -1131,6 +1087,7 @@ handle_seek_event (GnlComposition * comp, GstEvent * event) comp->priv->next_base_time = 0; seek_handling (comp, TRUE, FALSE); + return TRUE; } static gboolean @@ -1148,7 +1105,11 @@ gnl_composition_event_handler (GstPad * ghostpad, GstObject * parent, { GstEvent *nevent; - handle_seek_event (comp, event); + if ((res = handle_seek_event (comp, event)) == FALSE) { + gst_event_unref (event); + event = NULL; + break; + } /* the incoming event might not be quite correct, we get a new proper * event to pass on to the children. */ @@ -1238,23 +1199,12 @@ gnl_composition_event_handler (GstPad * ghostpad, GstObject * parent, break; } - if (res && priv->ghostpad) { - COMP_OBJECTS_LOCK (comp); - - /* If the timeline isn't entirely reconstructed, we silently ignore the - * event. In the case of seeks the pipeline will already be correctly - * configured at this point*/ - if (priv->waitingpads == 0) { - COMP_OBJECTS_UNLOCK (comp); - GST_DEBUG_OBJECT (comp, "About to call gnl_event_pad_func()"); - res = priv->gnl_event_pad_func (priv->ghostpad, parent, event); - priv->reset_time = FALSE; - GST_DEBUG_OBJECT (comp, "Done calling gnl_event_pad_func() %d", res); - } else { - COMP_OBJECTS_UNLOCK (comp); - gst_event_unref (event); - } - + if (res) { + GST_DEBUG_OBJECT (comp, "About to call gnl_event_pad_func: %p", + priv->gnl_event_pad_func); + res = priv->gnl_event_pad_func (GNL_OBJECT (comp)->srcpad, parent, event); + priv->reset_time = FALSE; + GST_DEBUG_OBJECT (comp, "Done calling gnl_event_pad_func() %d", res); } beach: @@ -1269,6 +1219,29 @@ pad_blocked (GstPad * pad, GstPadProbeInfo * info, GnlComposition * comp) return GST_PAD_PROBE_OK; } +static inline void +gnl_composition_reset_target_pad (GnlComposition * comp) +{ + GnlCompositionPrivate *priv = comp->priv; + + GST_DEBUG_OBJECT (comp, "Removing ghostpad"); + + if (priv->ghosteventprobe) { + GstPad *target; + + target = gst_ghost_pad_get_target ((GstGhostPad *) GNL_OBJECT_SRC (comp)); + if (target) + gst_pad_remove_probe (target, priv->ghosteventprobe); + priv->ghosteventprobe = 0; + } + + gnl_object_ghost_pad_set_target (GNL_OBJECT (comp), + GNL_OBJECT_SRC (comp), NULL); + priv->toplevelentry = NULL; + GST_ERROR ("NEED STRAM START"); + priv->send_stream_start = TRUE; +} + static GstPadProbeReturn drop_data (GstPad * pad, GstPadProbeInfo * info, GnlCompositionEntry * entry) { @@ -1296,104 +1269,64 @@ drop_data (GstPad * pad, GstPadProbeInfo * info, GnlCompositionEntry * entry) return GST_PAD_PROBE_OK; } -static inline void -gnl_composition_remove_ghostpad (GnlComposition * comp) -{ - GnlCompositionPrivate *priv = comp->priv; - - GST_DEBUG_OBJECT (comp, "Removing ghostpad"); - - if (priv->ghosteventprobe) { - GstPad *target; - - target = gst_ghost_pad_get_target ((GstGhostPad *) priv->ghostpad); - if (target) - gst_pad_remove_probe (target, priv->ghosteventprobe); - priv->ghosteventprobe = 0; - } - - gnl_object_remove_ghost_pad (GNL_OBJECT (comp), priv->ghostpad); - priv->ghostpad = NULL; - priv->toplevelentry = NULL; - priv->send_stream_start = TRUE; -} - /* gnl_composition_ghost_pad_set_target: * target: The target #GstPad. The refcount will be decremented (given to the ghostpad). * entry: The GnlCompositionEntry to which the pad belongs */ - static void gnl_composition_ghost_pad_set_target (GnlComposition * comp, GstPad * target, GnlCompositionEntry * entry) { + GstPad *ptarget; GnlCompositionPrivate *priv = comp->priv; - gboolean hadghost = priv->ghostpad ? TRUE : FALSE; if (target) - GST_DEBUG_OBJECT (comp, "target:%s:%s , hadghost:%d", - GST_DEBUG_PAD_NAME (target), hadghost); + GST_DEBUG_OBJECT (comp, "target:%s:%s", GST_DEBUG_PAD_NAME (target)); else - GST_DEBUG_OBJECT (comp, "Removing target, hadghost:%d", hadghost); + GST_DEBUG_OBJECT (comp, "Removing target"); - if (!hadghost) { - /* Create new ghostpad */ - GstPad *ghostpad = - gnl_object_ghost_pad_no_target ((GnlObject *) comp, "src", GST_PAD_SRC); - if (!priv->gnl_event_pad_func) { - GST_DEBUG_OBJECT (ghostpad, "About to replace event_pad_func"); - priv->gnl_event_pad_func = GST_PAD_EVENTFUNC (ghostpad); - } - - gst_pad_set_event_function (ghostpad, - GST_DEBUG_FUNCPTR (gnl_composition_event_handler)); - GST_DEBUG_OBJECT (ghostpad, "eventfunc is now %s", - GST_DEBUG_FUNCPTR_NAME (GST_PAD_EVENTFUNC (ghostpad))); + ptarget = + gst_ghost_pad_get_target (GST_GHOST_PAD (GNL_OBJECT (comp)->srcpad)); + if (ptarget && ptarget == target) { + GST_DEBUG_OBJECT (comp, + "Target of srcpad is the same as existing one, not changing"); + gst_object_unref (ptarget); + return; + } - priv->ghostpad = ghostpad; - } else { - GstPad *ptarget = gst_ghost_pad_get_target (GST_GHOST_PAD (priv->ghostpad)); + /* Unset previous target */ + if (ptarget) { + GST_DEBUG_OBJECT (comp, "Previous target was %s:%s", + GST_DEBUG_PAD_NAME (ptarget)); - if (ptarget && ptarget == target) { - GST_DEBUG_OBJECT (comp, - "Target of ghostpad is the same as existing one, not changing"); - gst_object_unref (ptarget); - return; + if (!priv->toplevelentry->probeid) { + /* If it's not blocked, block it */ + priv->toplevelentry->probeid = + gst_pad_add_probe (ptarget, + GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM | GST_PAD_PROBE_TYPE_IDLE, + (GstPadProbeCallback) pad_blocked, comp, NULL); } - /* Unset previous target */ - if (ptarget) { - GST_DEBUG_OBJECT (comp, "Previous target was %s:%s", - GST_DEBUG_PAD_NAME (ptarget)); - - if (!priv->toplevelentry->probeid) { - /* If it's not blocked, block it */ - priv->toplevelentry->probeid = - gst_pad_add_probe (ptarget, - GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM | GST_PAD_PROBE_TYPE_IDLE, - (GstPadProbeCallback) pad_blocked, comp, NULL); - } - - if (!priv->toplevelentry->dataprobeid) { - priv->toplevelentry->dataprobeid = gst_pad_add_probe (ptarget, - GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | - GST_PAD_PROBE_TYPE_EVENT_BOTH, (GstPadProbeCallback) drop_data, - priv->toplevelentry, NULL); - } - - /* remove event probe */ - if (priv->ghosteventprobe) { - gst_pad_remove_probe (ptarget, priv->ghosteventprobe); - priv->ghosteventprobe = 0; - } - gst_object_unref (ptarget); + if (!priv->toplevelentry->dataprobeid) { + priv->toplevelentry->dataprobeid = gst_pad_add_probe (ptarget, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | + GST_PAD_PROBE_TYPE_EVENT_BOTH, (GstPadProbeCallback) drop_data, + priv->toplevelentry, NULL); + } + /* remove event probe */ + if (priv->ghosteventprobe) { + gst_pad_remove_probe (ptarget, priv->ghosteventprobe); + priv->ghosteventprobe = 0; } + gst_object_unref (ptarget); + } /* Actually set the target */ - gnl_object_ghost_pad_set_target ((GnlObject *) comp, priv->ghostpad, target); + gnl_object_ghost_pad_set_target ((GnlObject *) comp, + GNL_OBJECT (comp)->srcpad, target); /* Set top-level entry (will be NULL if unsetting) */ priv->toplevelentry = entry; @@ -1406,17 +1339,6 @@ gnl_composition_ghost_pad_set_target (GnlComposition * comp, GstPad * target, GST_DEBUG_OBJECT (comp, "added event probe %lu", priv->ghosteventprobe); } - if (!hadghost) { - gst_pad_set_active (priv->ghostpad, TRUE); - - COMP_OBJECTS_UNLOCK (comp); - if (!gst_element_add_pad (GST_ELEMENT (comp), priv->ghostpad)) - GST_WARNING ("Couldn't add the ghostpad"); - else - gst_element_no_more_pads (GST_ELEMENT (comp)); - COMP_OBJECTS_LOCK (comp); - } - GST_DEBUG_OBJECT (comp, "END"); } @@ -1780,52 +1702,6 @@ get_clean_toplevel_stack (GnlComposition * comp, GstClockTime * timestamp, } -/* - * - * UTILITY FUNCTIONS - * - */ - -/* - * get_src_pad: - * element: a #GstElement - * - * Returns: The src pad for the given element. A reference was added to the - * returned pad, remove it when you don't need that pad anymore. - * Returns NULL if there's no source pad. - */ -static GstPad * -get_src_pad (GstElement * element) -{ - GstIterator *it; - GstIteratorResult itres; - GValue item = { 0, }; - GstPad *srcpad; - - it = gst_element_iterate_src_pads (element); - - itres = gst_iterator_next (it, &item); - if (itres != GST_ITERATOR_OK) { - GST_DEBUG ("%s doesn't have a src pad !", GST_ELEMENT_NAME (element)); - srcpad = NULL; - } else { - srcpad = g_value_get_object (&item); - gst_object_ref (srcpad); - g_value_reset (&item); - } - - gst_iterator_free (it); - - return srcpad; -} - - -/* - * - * END OF UTILITY FUNCTIONS - * - */ - static gboolean set_child_caps (GValue * item, GValue * ret G_GNUC_UNUSED, GnlObject * comp) { @@ -1866,8 +1742,7 @@ update_pipeline_func (GnlComposition * comp) /* If we're at the end, post SEGMENT_DONE, or push EOS */ GST_DEBUG_OBJECT (comp, "Nothing else to play"); - if (!(priv->segment->flags & GST_SEEK_FLAG_SEGMENT) - && priv->ghostpad) { + if (!(priv->segment->flags & GST_SEEK_FLAG_SEGMENT)) { GST_DEBUG_OBJECT (comp, "Real EOS should be sent now"); } else if (priv->segment->flags & GST_SEEK_FLAG_SEGMENT) { gint64 epos; @@ -1882,7 +1757,7 @@ update_pipeline_func (GnlComposition * comp) gst_element_post_message (GST_ELEMENT_CAST (comp), gst_message_new_segment_done (GST_OBJECT (comp), priv->segment->format, epos)); - gst_pad_push_event (priv->ghostpad, + gst_pad_push_event (GNL_OBJECT (comp)->srcpad, gst_event_new_segment_done (priv->segment->format, epos)); } } @@ -2118,144 +1993,6 @@ update_start_stop_duration (GnlComposition * comp) GST_TIME_ARGS (cobj->stop), GST_TIME_ARGS (cobj->duration)); } -static void -no_more_pads_object_cb (GstElement * element, GnlComposition * comp) -{ - GnlCompositionPrivate *priv = comp->priv; - GnlObject *object = (GnlObject *) element; - GNode *tmp; - GstPad *pad = NULL; - GnlCompositionEntry *entry; - - GST_LOG_OBJECT (comp, "no more pads on element %s", - GST_ELEMENT_NAME (element)); - - if (!(pad = get_src_pad (element))) - goto no_source; - - COMP_OBJECTS_LOCK (comp); - - if (G_UNLIKELY (priv->current == NULL)) { - GST_DEBUG_OBJECT (comp, "current stack is empty !"); - goto done; - } - - tmp = g_node_find (priv->current, G_IN_ORDER, G_TRAVERSE_ALL, object); - - if (G_UNLIKELY (tmp == NULL)) - goto not_in_stack; - - entry = COMP_ENTRY (comp, object); - wait_no_more_pads (comp, object, entry, FALSE); - - if (tmp->parent) { - GstElement *parent = (GstElement *) tmp->parent->data; - GstPad *sinkpad; - - /* Get an unlinked sinkpad from the parent */ - sinkpad = get_unlinked_sink_ghost_pad ((GnlOperation *) parent); - - if (G_UNLIKELY (sinkpad == NULL)) { - GST_WARNING_OBJECT (comp, - "Couldn't find an unlinked sinkpad from %s", - GST_ELEMENT_NAME (parent)); - goto done; - } - - /* Link pad to parent sink pad */ - if (G_UNLIKELY (gst_pad_link_full (pad, sinkpad, - GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK)) { - GST_WARNING_OBJECT (comp, "Failed to link pads %s:%s - %s:%s", - GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (sinkpad)); - gst_object_unref (sinkpad); - goto done; - } - - /* inform operation of incoming stream priority */ - gnl_operation_signal_input_priority_changed ((GnlOperation *) parent, - sinkpad, object->priority); - gst_object_unref (sinkpad); - gst_pad_remove_probe (pad, entry->probeid); - entry->probeid = 0; - } - - /* If there are no more waiting pads, activate the current stack */ - if (priv->current && (priv->waitingpads == 0) - && priv->stackvalid) { - GnlCompositionEntry *topentry = COMP_ENTRY (comp, priv->current->data); - GstPad *tpad = NULL; - - /* There are no more waiting pads for the currently configured timeline */ - /* stack. */ - tpad = get_src_pad (GST_ELEMENT (priv->current->data)); - GST_LOG_OBJECT (comp, - "top-level pad %s:%s, Setting target of ghostpad to it", - GST_DEBUG_PAD_NAME (tpad)); - - /* 2. send pending seek */ - if (priv->childseek) { - GstEvent *childseek = priv->childseek; - - priv->childseek = NULL; - GST_INFO_OBJECT (comp, "Sending pending seek on %s:%s", - GST_DEBUG_PAD_NAME (tpad)); - - COMP_OBJECTS_UNLOCK (comp); - - if (!(gst_pad_send_event (tpad, childseek))) - GST_ERROR_OBJECT (comp, "Sending seek event failed!"); - - COMP_OBJECTS_LOCK (comp); - } - priv->childseek = NULL; - - /* 1. set target of ghostpad to toplevel element src pad */ - gnl_composition_ghost_pad_set_target (comp, tpad, topentry); - - /* Check again if the top-level element is still in the stack */ - if (priv->current && - g_node_find (priv->current, G_IN_ORDER, G_TRAVERSE_ALL, object)) { - - /* 3. unblock ghostpad */ - if (topentry->probeid) { - GST_LOG_OBJECT (comp, "About to unblock top-level pad : %s:%s", - GST_DEBUG_PAD_NAME (tpad)); - gst_pad_remove_probe (tpad, topentry->probeid); - topentry->probeid = 0; - GST_LOG_OBJECT (comp, "Unblocked top-level pad"); - } - } else - GST_DEBUG ("Element went away from currently configured stack"); - - if (tpad) - gst_object_unref (tpad); - } - -done: - COMP_OBJECTS_UNLOCK (comp); - - if (pad) - gst_object_unref (pad); - - GST_DEBUG_OBJECT (comp, "end"); - - return; - -no_source: - { - GST_LOG_OBJECT (comp, "no source pad"); - return; - } - -not_in_stack: - { - GST_LOG_OBJECT (comp, - "The following object is not in currently configured stack : %s", - GST_ELEMENT_NAME (object)); - goto done; - } -} - /* * recursive depth-first relink stack function on new stack * @@ -2265,7 +2002,6 @@ not_in_stack: * * WITH OBJECTS LOCK TAKEN */ - static void compare_relink_single_node (GnlComposition * comp, GNode * node, GNode * oldstack) @@ -2292,10 +2028,11 @@ compare_relink_single_node (GnlComposition * comp, GNode * node, GST_DEBUG_OBJECT (comp, "newobj:%s", GST_ELEMENT_NAME ((GstElement *) newobj)); - srcpad = get_src_pad ((GstElement *) newobj); + + srcpad = GNL_OBJECT_SRC (newobj); /* 1. Make sure the source pad is blocked for new objects */ - if (G_UNLIKELY (!oldnode && srcpad)) { + if (G_UNLIKELY (!oldnode)) { GnlCompositionEntry *oldentry = COMP_ENTRY (comp, newobj); if (!oldentry->probeid) { GST_LOG_OBJECT (comp, "block_async(%s:%s, TRUE)", @@ -2314,59 +2051,48 @@ compare_relink_single_node (GnlComposition * comp, GNode * node, } entry = COMP_ENTRY (comp, newobj); - /* 2. link to parent if needed. - * - * If entry->nomorepadshandler is not zero, it means that srcpad didn't exist - * before and so we connected to no-more-pads. This can happen since there's a - * window of time between gnlsource adds its srcpad and then emits - * no-more-pads. In that case, we just wait for no-more-pads to be emitted. - */ - if (srcpad && entry->nomorepadshandler == 0) { - GST_LOG_OBJECT (comp, "has a valid source pad"); - /* POST PROCESSING */ - if ((oldparent != newparent) || - (oldparent && newparent && - (g_node_child_index (node, - newobj) != g_node_child_index (oldnode, newobj)))) { - GST_LOG_OBJECT (comp, - "not same parent, or same parent but in different order"); - /* relink to new parent in required order */ - if (newparent) { - GstPad *sinkpad; - GST_LOG_OBJECT (comp, "Linking %s and %s", - GST_ELEMENT_NAME (GST_ELEMENT (newobj)), - GST_ELEMENT_NAME (GST_ELEMENT (newparent))); - sinkpad = get_unlinked_sink_ghost_pad ((GnlOperation *) newparent); - if (G_UNLIKELY (sinkpad == NULL)) { - GST_WARNING_OBJECT (comp, - "Couldn't find an unlinked sinkpad from %s", - GST_ELEMENT_NAME (newparent)); - } else { - if (G_UNLIKELY (gst_pad_link_full (srcpad, sinkpad, - GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK)) { - GST_WARNING_OBJECT (comp, "Failed to link pads %s:%s - %s:%s", - GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad)); - } - gst_object_unref (sinkpad); + /* 2. link to parent if needed. */ + GST_LOG_OBJECT (comp, "has a valid source pad"); + /* POST PROCESSING */ + if ((oldparent != newparent) || + (oldparent && newparent && + (g_node_child_index (node, + newobj) != g_node_child_index (oldnode, newobj)))) { + GST_LOG_OBJECT (comp, + "not same parent, or same parent but in different order"); + /* relink to new parent in required order */ + if (newparent) { + GstPad *sinkpad; + GST_LOG_OBJECT (comp, "Linking %s and %s", + GST_ELEMENT_NAME (GST_ELEMENT (newobj)), + GST_ELEMENT_NAME (GST_ELEMENT (newparent))); + sinkpad = get_unlinked_sink_ghost_pad ((GnlOperation *) newparent); + if (G_UNLIKELY (sinkpad == NULL)) { + GST_WARNING_OBJECT (comp, + "Couldn't find an unlinked sinkpad from %s", + GST_ELEMENT_NAME (newparent)); + } else { + if (G_UNLIKELY (gst_pad_link_full (srcpad, sinkpad, + GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK)) { + GST_WARNING_OBJECT (comp, "Failed to link pads %s:%s - %s:%s", + GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad)); } + gst_object_unref (sinkpad); } - } else - GST_LOG_OBJECT (newobj, "Same parent and same position in the new stack"); - /* If there's an operation, inform it about priority changes */ - if (newparent) { - sinkpad = gst_pad_get_peer (srcpad); - gnl_operation_signal_input_priority_changed ((GnlOperation *) - newparent, sinkpad, newobj->priority); - gst_object_unref (sinkpad); } - - } else if (entry->nomorepadshandler) { - GST_INFO_OBJECT (newobj, - "we have a pad but we are connected to 'no-more-pads'"); } else { - wait_no_more_pads (comp, newobj, entry, TRUE); + GST_LOG_OBJECT (newobj, "Same parent and same position in the new stack"); } + /* If there's an operation, inform it about priority changes */ + if (newparent) { + sinkpad = gst_pad_get_peer (srcpad); + gnl_operation_signal_input_priority_changed ((GnlOperation *) + newparent, sinkpad, newobj->priority); + gst_object_unref (sinkpad); + } + + /* 3. Handle children */ if (GNL_IS_OPERATION (newobj)) { guint nbchildren = g_node_n_children (node); @@ -2391,15 +2117,12 @@ compare_relink_single_node (GnlComposition * comp, GNode * node, } /* 4. Unblock source pad */ - if ((srcpad && entry->nomorepadshandler == 0) && !G_NODE_IS_ROOT (node) && - entry->probeid) { + if (!G_NODE_IS_ROOT (node) && entry->probeid) { GST_LOG_OBJECT (comp, "Unblocking pad %s:%s", GST_DEBUG_PAD_NAME (srcpad)); gst_pad_remove_probe (srcpad, entry->probeid); entry->probeid = 0; } - if (G_LIKELY (srcpad)) - gst_object_unref (srcpad); GST_LOG_OBJECT (comp, "done with object %s", GST_ELEMENT_NAME (GST_ELEMENT (newobj))); } @@ -2416,7 +2139,6 @@ compare_relink_single_node (GnlComposition * comp, GNode * node, * * WITH OBJECTS LOCK TAKEN */ - static GList * compare_deactivate_single_node (GnlComposition * comp, GNode * node, GNode * newstack, gboolean modify) @@ -2427,6 +2149,8 @@ compare_deactivate_single_node (GnlComposition * comp, GNode * node, GList *deactivate = NULL; GnlObject *oldobj = NULL; GstPad *srcpad = NULL; + GstPad *peerpad = NULL; + GnlCompositionEntry *entry; if (G_UNLIKELY (!node)) return NULL; @@ -2443,46 +2167,40 @@ compare_deactivate_single_node (GnlComposition * comp, GNode * node, GST_DEBUG_OBJECT (comp, "oldobj:%s", GST_ELEMENT_NAME ((GstElement *) oldobj)); - srcpad = get_src_pad ((GstElement *) oldobj); - - if (G_LIKELY (srcpad)) { - GstPad *peerpad = NULL; - GnlCompositionEntry *entry = COMP_ENTRY (comp, oldobj); - - /* 1. Block source pad - * This makes sure that no data/event flow will come out of this element after this - * point. - * - * If entry is NULL, this means the element is in the process of being removed. - */ - if (entry && !entry->probeid) { - GST_LOG_OBJECT (comp, "Setting BLOCKING probe on %s:%s", - GST_DEBUG_PAD_NAME (srcpad)); - entry->probeid = - gst_pad_add_probe (srcpad, - GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM | GST_PAD_PROBE_TYPE_IDLE, - (GstPadProbeCallback) pad_blocked, comp, NULL); - } - if (entry && !entry->dataprobeid) { - entry->dataprobeid = gst_pad_add_probe (srcpad, - GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | - GST_PAD_PROBE_TYPE_EVENT_BOTH, (GstPadProbeCallback) drop_data, entry, - NULL); - } + srcpad = GNL_OBJECT_SRC (oldobj); - /* 2. If we have to modify or we have a parent, flush downstream - * This ensures the streaming thread going through the current object has - * either stopped or is blocking against the source pad. */ - if ((modify || oldparent) && (peerpad = gst_pad_get_peer (srcpad))) { - GST_LOG_OBJECT (comp, "Sending flush start/stop downstream "); - gst_pad_send_event (peerpad, gst_event_new_flush_start ()); - gst_pad_send_event (peerpad, gst_event_new_flush_stop (TRUE)); - GST_DEBUG_OBJECT (comp, "DONE Sending flush events downstream"); - gst_object_unref (peerpad); - } + entry = COMP_ENTRY (comp, oldobj); - } else { - GST_LOG_OBJECT (comp, "No source pad available"); + /* 1. Block source pad + * This makes sure that no data/event flow will come out of this element after this + * point. + * + * If entry is NULL, this means the element is in the process of being removed. + */ + if (entry && !entry->probeid) { + GST_LOG_OBJECT (comp, "Setting BLOCKING probe on %s:%s", + GST_DEBUG_PAD_NAME (srcpad)); + entry->probeid = + gst_pad_add_probe (srcpad, + GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM | GST_PAD_PROBE_TYPE_IDLE, + (GstPadProbeCallback) pad_blocked, comp, NULL); + } + if (entry && !entry->dataprobeid) { + entry->dataprobeid = gst_pad_add_probe (srcpad, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | + GST_PAD_PROBE_TYPE_EVENT_BOTH, (GstPadProbeCallback) drop_data, entry, + NULL); + } + + /* 2. If we have to modify or we have a parent, flush downstream + * This ensures the streaming thread going through the current object has + * either stopped or is blocking against the source pad. */ + if ((modify || oldparent) && (peerpad = gst_pad_get_peer (srcpad))) { + GST_LOG_OBJECT (comp, "Sending flush start/stop downstream "); + gst_pad_send_event (peerpad, gst_event_new_flush_start ()); + gst_pad_send_event (peerpad, gst_event_new_flush_stop (TRUE)); + GST_DEBUG_OBJECT (comp, "DONE Sending flush events downstream"); + gst_object_unref (peerpad); } /* 3. Unlink from the parent if we've changed position */ @@ -2492,11 +2210,7 @@ compare_deactivate_single_node (GnlComposition * comp, GNode * node, if (G_UNLIKELY (!oldparent)) { GST_LOG_OBJECT (comp, "Top-level object"); /* for top-level objects we just set the ghostpad target to NULL */ - if (comp->priv->ghostpad) { - GST_LOG_OBJECT (comp, "Setting ghostpad target to NULL"); - gnl_composition_ghost_pad_set_target (comp, NULL, NULL); - } else - GST_LOG_OBJECT (comp, "No ghostpad"); + gnl_composition_ghost_pad_set_target (comp, NULL, NULL); } else { GnlObject *newparent = NULL; @@ -2514,7 +2228,7 @@ compare_deactivate_single_node (GnlComposition * comp, GNode * node, GST_LOG_OBJECT (comp, "Topology changed, unlinking from downstream"); - if (srcpad && (peerpad = gst_pad_get_peer (srcpad))) { + if ((peerpad = gst_pad_get_peer (srcpad))) { GST_LOG_OBJECT (peerpad, "Sending flush start/stop"); gst_pad_send_event (peerpad, gst_event_new_flush_start ()); gst_pad_send_event (peerpad, gst_event_new_flush_stop (TRUE)); @@ -2544,8 +2258,6 @@ compare_deactivate_single_node (GnlComposition * comp, GNode * node, deactivate = g_list_prepend (deactivate, oldobj); } - if (G_LIKELY (srcpad)) - gst_object_unref (srcpad); GST_LOG_OBJECT (comp, "done with object %s", GST_ELEMENT_NAME (GST_ELEMENT (oldobj))); @@ -2717,23 +2429,14 @@ update_pipeline (GnlComposition * comp, GstClockTime currenttime, priv->segment_stop = currenttime; } - /* 4. Clear pending child seek - * We'll be creating a new one */ - if (priv->childseek) { - GST_DEBUG ("unreffing event %p", priv->childseek); - gst_event_unref (priv->childseek); - priv->childseek = NULL; - } - /* Invalidate current stack */ if (priv->current) g_node_destroy (priv->current); priv->current = NULL; - /* 5. deactivate unused elements */ + /* 4. deactivate unused elements */ if (todeactivate) { GList *tmp; - GnlCompositionEntry *entry; GstElement *element; GST_DEBUG_OBJECT (comp, "De-activating objects no longer used"); @@ -2744,13 +2447,6 @@ update_pipeline (GnlComposition * comp, GstClockTime currenttime, gst_element_set_state (element, priv->deactivated_elements_state); gst_element_set_locked_state (element, TRUE); - entry = COMP_ENTRY (comp, element); - - /* entry can be NULL here if update_pipeline was called by - * gnl_composition_remove_object (comp, tmp->data) - */ - if (entry && entry->nomorepadshandler) - wait_no_more_pads (comp, element, entry, FALSE); } g_list_free (todeactivate); @@ -2758,7 +2454,7 @@ update_pipeline (GnlComposition * comp, GstClockTime currenttime, GST_DEBUG_OBJECT (comp, "Finished de-activating objects no longer used"); } - /* 6. Unlock all elements in new stack */ + /* 5. Unlock all elements in new stack */ GST_DEBUG_OBJECT (comp, "Setting current stack"); priv->current = stack; @@ -2769,13 +2465,16 @@ update_pipeline (GnlComposition * comp, GstClockTime currenttime, GST_DEBUG_OBJECT (comp, "Finished activating objects in new stack"); } - /* 7. Activate stack (might happen asynchronously) */ + /* 6. Activate stack (might happen asynchronously) */ if (priv->current) { GstEvent *event; + GstPad *pad; + GstElement *topelement; + GnlCompositionEntry *topentry; priv->stackvalid = TRUE; - /* 7.1. Create new seek event for newly configured timeline stack */ + /* 6.1. Create new seek event for newly configured timeline stack */ if (samestack && (startchanged || stopchanged)) event = get_new_seek_event (comp, @@ -2783,60 +2482,38 @@ update_pipeline (GnlComposition * comp, GstClockTime currenttime, else event = get_new_seek_event (comp, initial, FALSE); - /* 7.2.a If the stack entirely ready, send seek out synchronously */ - if (priv->waitingpads == 0) { - GstPad *pad; - GstElement *topelement = GST_ELEMENT (priv->current->data); - - /* Get toplevel object source pad */ - if ((pad = get_src_pad (topelement))) { - GnlCompositionEntry *topentry = COMP_ENTRY (comp, topelement); - - GST_DEBUG_OBJECT (comp, - "We have a valid toplevel element pad %s:%s", - GST_DEBUG_PAD_NAME (pad)); - - /* Send seek event */ - GST_LOG_OBJECT (comp, "sending seek event"); - if (gst_pad_send_event (pad, event)) { - /* Unconditionnaly set the ghostpad target to pad */ - GST_LOG_OBJECT (comp, - "Setting the composition's ghostpad target to %s:%s", - GST_DEBUG_PAD_NAME (pad)); + /* 6.2 The stack is entirely ready, send seek out synchronously */ + topelement = GST_ELEMENT (priv->current->data); + /* Get toplevel object source pad */ + pad = GNL_OBJECT_SRC (topelement); + topentry = COMP_ENTRY (comp, topelement); - gnl_composition_ghost_pad_set_target (comp, pad, topentry); + GST_DEBUG_OBJECT (comp, + "We have a valid toplevel element pad %s:%s", GST_DEBUG_PAD_NAME (pad)); - if (topentry->probeid) { + /* Send seek event */ + GST_LOG_OBJECT (comp, "sending seek event"); + if (gst_pad_send_event (pad, event)) { + /* Unconditionnaly set the ghostpad target to pad */ + GST_LOG_OBJECT (comp, + "Setting the composition's ghostpad target to %s:%s", + GST_DEBUG_PAD_NAME (pad)); - /* unblock top-level pad */ - GST_LOG_OBJECT (comp, "About to unblock top-level srcpad"); - gst_pad_remove_probe (pad, topentry->probeid); - topentry->probeid = 0; - } - } else { - ret = FALSE; - } - gst_object_unref (pad); + gnl_composition_ghost_pad_set_target (comp, pad, topentry); - } else { - GST_WARNING_OBJECT (comp, - "Timeline is entirely linked, but couldn't get top-level element's source pad"); + if (topentry->probeid) { - ret = FALSE; + /* unblock top-level pad */ + GST_LOG_OBJECT (comp, "About to unblock top-level srcpad"); + gst_pad_remove_probe (pad, topentry->probeid); + topentry->probeid = 0; } } else { - /* 7.2.b. Stack isn't entirely ready, save seek event for later on */ - GST_LOG_OBJECT (comp, - "The timeline stack isn't entirely linked, delaying sending seek event (waitingpads:%d)", - priv->waitingpads); - - priv->childseek = event; - ret = TRUE; + ret = FALSE; } } else { - if ((!priv->objects_start) && priv->ghostpad) { - GST_DEBUG_OBJECT (comp, "composition is now empty, removing ghostpad"); - gnl_composition_remove_ghostpad (comp); + if ((!priv->objects_start)) { + gnl_composition_reset_target_pad (comp); priv->segment_start = 0; priv->segment_stop = GST_CLOCK_TIME_NONE; } @@ -2846,65 +2523,6 @@ update_pipeline (GnlComposition * comp, GstClockTime currenttime, return ret; } -/* - * Child modification updates - */ - -static void -object_pad_removed (GnlObject * object, GstPad * pad, GnlComposition * comp) -{ - GnlCompositionPrivate *priv = comp->priv; - - GST_DEBUG_OBJECT (comp, "pad %s:%s was removed", GST_DEBUG_PAD_NAME (pad)); - - if (GST_PAD_IS_SRC (pad)) { - /* remove ghostpad if it's the current top stack object */ - if (priv->current && GNL_OBJECT (priv->current->data) == object - && priv->ghostpad) - gnl_composition_remove_ghostpad (comp); - else { - GnlCompositionEntry *entry = COMP_ENTRY (comp, object); - - if (entry && entry->probeid) { - gst_pad_remove_probe (pad, entry->probeid); - entry->probeid = 0; - } - if (entry && entry->dataprobeid) { - gst_pad_remove_probe (pad, entry->dataprobeid); - entry->dataprobeid = 0; - } - } - } -} - -static void -object_pad_added (GnlObject * object G_GNUC_UNUSED, GstPad * pad, - GnlComposition * comp) -{ - GnlCompositionEntry *entry; - - if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) - return; - - entry = COMP_ENTRY (comp, object); - - if (!entry->probeid) { - GST_DEBUG_OBJECT (comp, "pad %s:%s was added, blocking it", - GST_DEBUG_PAD_NAME (pad)); - entry->probeid = - gst_pad_add_probe (pad, - GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM | GST_PAD_PROBE_TYPE_IDLE, - (GstPadProbeCallback) pad_blocked, comp, NULL); - } - - if (!entry->dataprobeid) { - entry->dataprobeid = gst_pad_add_probe (pad, - GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | - GST_PAD_PROBE_TYPE_EVENT_BOTH, (GstPadProbeCallback) drop_data, entry, - NULL); - } -} - static gboolean gnl_composition_add_object (GstBin * bin, GstElement * element) { @@ -2967,10 +2585,15 @@ gnl_composition_add_object (GstBin * bin, GstElement * element) /* ...and add it to the hash table */ g_hash_table_insert (priv->objects_hash, element, entry); - entry->padremovedhandler = g_signal_connect (G_OBJECT (element), - "pad-removed", G_CALLBACK (object_pad_removed), comp); - entry->padaddedhandler = g_signal_connect (G_OBJECT (element), - "pad-added", G_CALLBACK (object_pad_added), comp); + entry->dataprobeid = gst_pad_add_probe (entry->object->srcpad, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | + GST_PAD_PROBE_TYPE_EVENT_BOTH, (GstPadProbeCallback) drop_data, entry, + NULL); + + entry->probeid = + gst_pad_add_probe (entry->object->srcpad, + GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM | GST_PAD_PROBE_TYPE_IDLE, + (GstPadProbeCallback) pad_blocked, comp, NULL); /* Set the caps of the composition */ if (G_UNLIKELY (!gst_caps_is_any (((GnlObject *) comp)->caps))) @@ -3034,8 +2657,6 @@ gnl_composition_remove_object (GstBin * bin, GstElement * element) goto out; } - if (entry->nomorepadshandler) - wait_no_more_pads (comp, element, entry, FALSE); gst_object_ref (element); gst_element_set_locked_state (element, FALSE); @@ -3069,6 +2690,7 @@ gnl_composition_remove_object (GstBin * bin, GstElement * element) /* Make it possible to reuse the same object later */ gnl_object_reset (GNL_OBJECT (element)); gst_object_unref (element); + out: return ret; } diff --git a/gnl/gnlghostpad.c b/gnl/gnlghostpad.c index 5db4e44..2902726 100644 --- a/gnl/gnlghostpad.c +++ b/gnl/gnlghostpad.c @@ -35,6 +35,8 @@ struct _GnlPadPrivate GstPadDirection dir; GstPadEventFunction eventfunc; GstPadQueryFunction queryfunc; + + GstEvent *pending_seek; }; static GstEvent * @@ -489,7 +491,18 @@ ghostpad_event_function (GstPad * ghostpad, GstObject * parent, { switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: + { + GstPad *target; + event = translate_incoming_seek (object, event); + if (!(target = gst_ghost_pad_get_target (GST_GHOST_PAD (ghostpad)))) { + priv->pending_seek = event; + GST_INFO_OBJECT (ghostpad, "No target set yet, " + "Will send the seek event when the target is set"); + ret = TRUE; + event = NULL; + } + } break; default: break; @@ -661,7 +674,7 @@ gnl_object_ghost_pad (GnlObject * object, const gchar * name, GstPad * target) g_return_val_if_fail (target, FALSE); g_return_val_if_fail ((dir != GST_PAD_UNKNOWN), FALSE); - ghost = gnl_object_ghost_pad_no_target (object, name, dir); + ghost = gnl_object_ghost_pad_no_target (object, name, dir, NULL); if (!ghost) { GST_WARNING_OBJECT (object, "Couldn't create ghostpad"); return NULL; @@ -692,17 +705,19 @@ gnl_object_ghost_pad (GnlObject * object, const gchar * name, GstPad * target) */ GstPad * gnl_object_ghost_pad_no_target (GnlObject * object, const gchar * name, - GstPadDirection dir) + GstPadDirection dir, GstPadTemplate * template) { GstPad *ghost; GnlPadPrivate *priv; /* create a no_target ghostpad */ - ghost = gst_ghost_pad_new_no_target (name, dir); + if (template) + ghost = gst_ghost_pad_new_no_target_from_template (name, template); + else + ghost = gst_ghost_pad_new_no_target (name, dir); if (!ghost) return NULL; - GST_DEBUG ("grabbing existing pad functions"); /* remember the existing ghostpad event/query/link/unlink functions */ priv = g_slice_new0 (GnlPadPrivate); @@ -726,6 +741,8 @@ gnl_object_ghost_pad_no_target (GnlObject * object, const gchar * name, return ghost; } + + void gnl_object_remove_ghost_pad (GnlObject * object, GstPad * ghost) { @@ -747,16 +764,32 @@ gnl_object_ghost_pad_set_target (GnlObject * object, GstPad * ghost, GnlPadPrivate *priv = gst_pad_get_element_private (ghost); g_return_val_if_fail (priv, FALSE); + g_return_val_if_fail (GST_IS_PAD (ghost), FALSE); - if (target) - GST_DEBUG_OBJECT (object, "setting target %s:%s on ghostpad", - GST_DEBUG_PAD_NAME (target)); - else - GST_DEBUG_OBJECT (object, "removing target from ghostpad"); + if (target) { + GST_DEBUG_OBJECT (object, "setting target %s:%s on %s:%s", + GST_DEBUG_PAD_NAME (target), GST_DEBUG_PAD_NAME (ghost)); + } else { + GST_ERROR_OBJECT (object, "removing target from ghostpad"); + priv->pending_seek = NULL; + } /* set target */ - if (!(gst_ghost_pad_set_target (GST_GHOST_PAD (ghost), target))) + if (!(gst_ghost_pad_set_target (GST_GHOST_PAD (ghost), target))) { + GST_WARNING_OBJECT (priv->object, "Could not set ghost %s:%s " + "target to: %s:%s", GST_DEBUG_PAD_NAME (ghost), + GST_DEBUG_PAD_NAME (target)); return FALSE; + } + + if (target && priv->pending_seek) { + gboolean res = gst_pad_send_event (ghost, priv->pending_seek); + + GST_INFO_OBJECT (object, "Sending our pending seek event: %" GST_PTR_FORMAT + " -- Result is %i", priv->pending_seek, res); + + priv->pending_seek = NULL; + } return TRUE; } diff --git a/gnl/gnlghostpad.h b/gnl/gnlghostpad.h index f43ab0d..a49924d 100644 --- a/gnl/gnlghostpad.h +++ b/gnl/gnlghostpad.h @@ -33,7 +33,7 @@ GstPad *gnl_object_ghost_pad (GnlObject * object, const gchar * name, GstPad * target); GstPad *gnl_object_ghost_pad_no_target (GnlObject * object, - const gchar * name, GstPadDirection dir); + const gchar * name, GstPadDirection dir, GstPadTemplate *templ); gboolean gnl_object_ghost_pad_set_target (GnlObject * object, GstPad * ghost, GstPad * target); diff --git a/gnl/gnlobject.c b/gnl/gnlobject.c index 0b749cd..5915817 100644 --- a/gnl/gnlobject.c +++ b/gnl/gnlobject.c @@ -42,10 +42,7 @@ GST_DEBUG_CATEGORY_STATIC (gnlobject_debug); #define GST_CAT_DEFAULT gnlobject_debug -#define _do_init \ - GST_DEBUG_CATEGORY_INIT (gnlobject_debug, "gnlobject", GST_DEBUG_FG_BLUE | GST_DEBUG_BOLD, "GNonLin Object base class"); -#define gnl_object_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GnlObject, gnl_object, GST_TYPE_BIN, _do_init); +static GObjectClass *parent_class = NULL; /**************************************************** * Helper macros * @@ -117,6 +114,9 @@ gnl_object_class_init (GnlObjectClass * klass) gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; gnlobject_class = (GnlObjectClass *) klass; + GST_DEBUG_CATEGORY_INIT (gnlobject_debug, "gnlobject", + GST_DEBUG_FG_BLUE | GST_DEBUG_BOLD, "GNonLin object"); + parent_class = g_type_class_ref (GST_TYPE_BIN); gobject_class->set_property = GST_DEBUG_FUNCPTR (gnl_object_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gnl_object_get_property); @@ -243,7 +243,7 @@ gnl_object_class_init (GnlObjectClass * klass) } static void -gnl_object_init (GnlObject * object) +gnl_object_init (GnlObject * object, GnlObjectClass * klass) { object->start = object->pending_start = 0; object->duration = object->pending_duration = 0; @@ -258,6 +258,12 @@ gnl_object_init (GnlObject * object) object->segment_rate = 1.0; object->segment_start = -1; object->segment_stop = -1; + + object->srcpad = gnl_object_ghost_pad_no_target (object, + "src", GST_PAD_SRC, + gst_element_class_get_pad_template ((GstElementClass *) klass, "src")); + + gst_element_add_pad (GST_ELEMENT (object), object->srcpad); } static void @@ -653,3 +659,30 @@ gnl_object_reset (GnlObject * object) object->priority = 0; object->active = TRUE; } + +GType +gnl_object_get_type (void) +{ + static volatile gsize type = 0; + + if (g_once_init_enter (&type)) { + GType _type; + static const GTypeInfo info = { + sizeof (GnlObjectClass), + NULL, + NULL, + (GClassInitFunc) gnl_object_class_init, + NULL, + NULL, + sizeof (GnlObject), + 0, + (GInstanceInitFunc) gnl_object_init, + }; + + _type = g_type_register_static (GST_TYPE_BIN, + "GnlObject", &info, G_TYPE_FLAG_ABSTRACT); + g_once_init_leave (&type, _type); + } + return type; + +} diff --git a/gnl/gnlobject.h b/gnl/gnlobject.h index 4ba7dd8..d27bed6 100644 --- a/gnl/gnlobject.h +++ b/gnl/gnlobject.h @@ -43,6 +43,8 @@ G_BEGIN_DECLS #define GNL_IS_OBJECT_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GNL_TYPE_OBJECT)) +#define GNL_OBJECT_SRC(obj) (((GnlObject *) obj)->srcpad) + /** * GnlObjectFlags: * @GNL_OBJECT_IS_SOURCE: @@ -84,6 +86,8 @@ struct _GnlObject { GstBin parent; + GstPad *srcpad; + /* Time positionning */ GstClockTime start; GstClockTime inpoint; diff --git a/gnl/gnloperation.c b/gnl/gnloperation.c index dcc811f..77c8f6c 100644 --- a/gnl/gnloperation.c +++ b/gnl/gnloperation.c @@ -40,7 +40,7 @@ static GstStaticPadTemplate gnl_operation_src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, - GST_PAD_SOMETIMES, + GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); static GstStaticPadTemplate gnl_operation_sink_template = @@ -163,10 +163,9 @@ gnl_operation_dispose (GObject * object) GnlOperation *oper = (GnlOperation *) object; GST_DEBUG_OBJECT (object, "Disposing of source pad"); - if (oper->ghostpad) { - gnl_object_remove_ghost_pad (GNL_OBJECT (oper), oper->ghostpad); - oper->ghostpad = NULL; - } + + gnl_object_ghost_pad_set_target (GNL_OBJECT (object), + GNL_OBJECT (object)->srcpad, NULL); GST_DEBUG_OBJECT (object, "Disposing of sink pad(s)"); while (oper->sinks) { @@ -190,7 +189,6 @@ static void gnl_operation_init (GnlOperation * operation) { gnl_operation_reset (operation); - operation->ghostpad = NULL; operation->element = NULL; } @@ -362,13 +360,8 @@ gnl_operation_add_element (GstBin * bin, GstElement * element) operation->element = element; operation->dynamicsinks = isdynamic; - /* Source ghostpad */ - if (operation->ghostpad) - gnl_object_ghost_pad_set_target (GNL_OBJECT (operation), - operation->ghostpad, srcpad); - else - operation->ghostpad = gnl_object_ghost_pad (GNL_OBJECT (operation), - GST_PAD_NAME (srcpad), srcpad); + gnl_object_ghost_pad_set_target (GNL_OBJECT (operation), + GNL_OBJECT (operation)->srcpad, srcpad); /* Remove the reference get_src_pad gave us */ gst_object_unref (srcpad); diff --git a/gnl/gnloperation.h b/gnl/gnloperation.h index 3d6454b..52ed82a 100644 --- a/gnl/gnloperation.h +++ b/gnl/gnloperation.h @@ -59,8 +59,6 @@ G_BEGIN_DECLS /* FIXME : We might need to use a lock to access this list */ GList * sinks; /* The sink ghostpads */ - GstPad *ghostpad; /* src ghostpad */ - GstElement *element; /* controlled element */ GstClockTime next_base_time; diff --git a/gnl/gnlsource.c b/gnl/gnlsource.c index 47ee8c7..5a5680f 100644 --- a/gnl/gnlsource.c +++ b/gnl/gnlsource.c @@ -35,7 +35,7 @@ static GstStaticPadTemplate gnl_source_src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, - GST_PAD_SOMETIMES, + GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); GST_DEBUG_CATEGORY_STATIC (gnlsource); @@ -51,7 +51,6 @@ struct _GnlSourcePrivate gboolean dispose_has_run; gboolean dynamicpads; /* TRUE if the controlled element has dynamic pads */ - GstPad *ghostpad; /* The source ghostpad */ GstEvent *event; /* queued event */ gulong padremovedid; /* signal handler for element pad-removed signal */ @@ -59,9 +58,10 @@ struct _GnlSourcePrivate gulong probeid; /* source pad probe id */ gboolean pendingblock; /* We have a pending pad_block */ - gboolean areblocked; /* We already got blocked */ + gboolean is_blocked; /* We already got blocked */ GstPad *ghostedpad; /* Pad (to be) ghosted */ GstPad *staticpad; /* The only pad. We keep an extra ref */ + gboolean got_seeked; }; static gboolean gnl_source_prepare (GnlObject * object); @@ -136,6 +136,7 @@ gnl_source_init (GnlSource * source) static void gnl_source_dispose (GObject * object) { + GnlObject *gnlobject = (GnlObject *) object; GnlSource *source = (GnlSource *) object; GnlSourcePrivate *priv = source->priv; @@ -153,9 +154,8 @@ gnl_source_dispose (GObject * object) if (priv->event) gst_event_unref (priv->event); - if (priv->ghostpad) - gnl_object_remove_ghost_pad ((GnlObject *) object, priv->ghostpad); - priv->ghostpad = NULL; + if (priv->ghostedpad) + gnl_object_ghost_pad_set_target (gnlobject, gnlobject->srcpad, NULL); if (priv->staticpad) { gst_object_unref (priv->staticpad); @@ -171,19 +171,20 @@ element_pad_added_cb (GstElement * element G_GNUC_UNUSED, GstPad * pad, { GstCaps *srccaps; GnlSourcePrivate *priv = source->priv; + GnlObject *gnlobject = (GnlObject *) source; GST_DEBUG_OBJECT (source, "pad %s:%s", GST_DEBUG_PAD_NAME (pad)); - if (priv->ghostpad || priv->pendingblock) { + if (priv->pendingblock) { GST_WARNING_OBJECT (source, - "We already have (pending) ghost-ed a valid source pad (ghostpad:%s:%s, pendingblock:%d", - GST_DEBUG_PAD_NAME (priv->ghostpad), priv->pendingblock); + "We already have (pending) ghost-ed a valid source pad (srcpad:%s:%s, pendingblock:%d", + GST_DEBUG_PAD_NAME (gnlobject->srcpad), priv->pendingblock); return; } /* FIXME: pass filter caps to query_caps directly */ srccaps = gst_pad_query_caps (pad, NULL); - if (!gst_caps_can_intersect (srccaps, GNL_OBJECT (source)->caps)) { + if (gnlobject->caps && !gst_caps_can_intersect (srccaps, gnlobject->caps)) { gst_caps_unref (srccaps); GST_DEBUG_OBJECT (source, "Pad doesn't have valid caps, ignoring"); return; @@ -210,6 +211,7 @@ element_pad_removed_cb (GstElement * element G_GNUC_UNUSED, GstPad * pad, GnlSource * source) { GnlSourcePrivate *priv = source->priv; + GnlObject *gnlobject = (GnlObject *) source; GST_DEBUG_OBJECT (source, "pad %s:%s (controlled pad %s:%s)", GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (priv->ghostedpad)); @@ -218,19 +220,17 @@ element_pad_removed_cb (GstElement * element G_GNUC_UNUSED, GstPad * pad, GST_DEBUG_OBJECT (source, "The removed pad is the controlled pad, clearing up"); - if (priv->ghostpad) { - GST_DEBUG_OBJECT (source, "Clearing up ghostpad"); + GST_DEBUG_OBJECT (source, "Clearing up ghostpad"); - priv->areblocked = FALSE; - if (priv->probeid) { - gst_pad_remove_probe (pad, priv->probeid); - priv->probeid = 0; - } - - gnl_object_remove_ghost_pad ((GnlObject *) source, priv->ghostpad); - priv->ghostpad = NULL; + priv->is_blocked = FALSE; + if (priv->probeid) { + gst_pad_remove_probe (pad, priv->probeid); + priv->probeid = 0; } + gnl_object_ghost_pad_set_target (GNL_OBJECT (source), gnlobject->srcpad, + NULL); + priv->pendingblock = FALSE; priv->ghostedpad = NULL; } else { @@ -292,20 +292,24 @@ ghost_seek_pad (GnlSource * source) { GnlSourcePrivate *priv = source->priv; GstPad *pad = priv->ghostedpad; + GnlObject *gnlobject = (GnlObject *) source; - if (priv->ghostpad || !pad) + priv->got_seeked = TRUE; + + if (!pad) goto beach; GST_DEBUG_OBJECT (source, "ghosting %s:%s", GST_DEBUG_PAD_NAME (pad)); - priv->ghostpad = gnl_object_ghost_pad ((GnlObject *) source, - GST_PAD_NAME (pad), pad); + gnl_object_ghost_pad_set_target (gnlobject, gnlobject->srcpad, pad); GST_DEBUG_OBJECT (source, "emitting no more pads"); - gst_pad_set_active (priv->ghostpad, TRUE); + + /*FIXME : do that when going to PAUSED */ + gst_pad_set_active (gnlobject->srcpad, TRUE); if (priv->event) { GST_DEBUG_OBJECT (source, "sending queued seek event"); - if (!(gst_pad_send_event (priv->ghostpad, priv->event))) + if (!(gst_pad_send_event (gnlobject->srcpad, priv->event))) GST_ELEMENT_ERROR (source, RESOURCE, SEEK, (NULL), ("Sending initial seek to upstream element failed")); else @@ -314,7 +318,7 @@ ghost_seek_pad (GnlSource * source) } GST_DEBUG_OBJECT (source, "about to unblock %s:%s", GST_DEBUG_PAD_NAME (pad)); - priv->areblocked = FALSE; + priv->is_blocked = FALSE; if (priv->probeid) { gst_pad_remove_probe (pad, priv->probeid); priv->probeid = 0; @@ -332,10 +336,10 @@ pad_blocked_cb (GstPad * pad, GstPadProbeInfo * info, GnlSource * source) { GST_DEBUG_OBJECT (pad, "probe callback"); - if (!source->priv->ghostpad && !source->priv->areblocked) { + if (!source->priv->got_seeked && !source->priv->is_blocked) { GThread *lthread; - source->priv->areblocked = TRUE; + source->priv->is_blocked = TRUE; GST_DEBUG_OBJECT (pad, "starting thread to call ghost_seek_pad"); lthread = g_thread_new ("gnlsourceseek", (GThreadFunc) ghost_seek_pad, source); @@ -439,6 +443,7 @@ static gboolean gnl_source_remove_element (GstBin * bin, GstElement * element) { GnlSource *source = (GnlSource *) bin; + GnlObject *gnlobject = (GnlObject *) element; GnlSourcePrivate *priv = source->priv; gboolean pret; @@ -452,11 +457,9 @@ gnl_source_remove_element (GstBin * bin, GstElement * element) } if (pret) { - /* remove ghostpad */ - if (priv->ghostpad) { - gnl_object_remove_ghost_pad ((GnlObject *) bin, priv->ghostpad); - priv->ghostpad = NULL; - } + gnl_object_ghost_pad_set_target (GNL_OBJECT (source), gnlobject->srcpad, + NULL); + priv->got_seeked = FALSE; /* discard events */ if (priv->event) { @@ -485,12 +488,13 @@ static gboolean gnl_source_send_event (GstElement * element, GstEvent * event) { GnlSource *source = (GnlSource *) element; + GnlObject *gnlobject = (GnlObject *) element; gboolean res = TRUE; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: - if (source->priv->ghostpad) - res = gst_pad_send_event (source->priv->ghostpad, event); + if (source->priv->ghostedpad) + res = gst_pad_send_event (gnlobject->srcpad, event); else { if (source->priv->event) gst_event_unref (source->priv->event); @@ -516,13 +520,15 @@ gnl_source_prepare (GnlObject * object) if (!source->element) { GST_WARNING_OBJECT (source, "GnlSource doesn't have an element to control !"); + if (parent) + gst_object_unref (parent); return FALSE; } - GST_LOG_OBJECT (source, "ghostpad:%p, dynamicpads:%d", - priv->ghostpad, priv->dynamicpads); + GST_LOG_OBJECT (source, "srcpad:%p, dynamicpads:%d", + object->srcpad, priv->dynamicpads); - if (!(priv->ghostpad) && !priv->pendingblock) { + if (!(priv->got_seeked) && !priv->pendingblock) { GstPad *pad; GST_LOG_OBJECT (source, "no ghostpad and no dynamic pads"); @@ -568,22 +574,22 @@ gnl_source_cleanup (GnlObject * object) GnlSource *source = GNL_SOURCE (object); GnlSourcePrivate *priv = source->priv; - if (priv->ghostpad) { - GstPad *target = gst_ghost_pad_get_target ((GstGhostPad *) priv->ghostpad); + /* FIXME : should just be ghostedpad */ + GstPad *target = gst_ghost_pad_get_target ((GstGhostPad *) object->srcpad); - if (target) { - if (priv->probeid) { - gst_pad_remove_probe (target, priv->probeid); - priv->probeid = 0; - } - gst_object_unref (target); + if (target) { + if (priv->probeid) { + gst_pad_remove_probe (target, priv->probeid); + priv->probeid = 0; } - gnl_object_remove_ghost_pad ((GnlObject *) source, priv->ghostpad); - priv->ghostpad = NULL; - priv->ghostedpad = NULL; - priv->areblocked = FALSE; - priv->pendingblock = FALSE; + gst_object_unref (target); } + gnl_object_ghost_pad_set_target (GNL_OBJECT (source), object->srcpad, NULL); + priv->got_seeked = FALSE; + priv->ghostedpad = NULL; + priv->is_blocked = FALSE; + priv->pendingblock = FALSE; + return TRUE; } diff --git a/tests/check/gnl/complex.c b/tests/check/gnl/complex.c index f4b7eb8..2f32a31 100644 --- a/tests/check/gnl/complex.c +++ b/tests/check/gnl/complex.c @@ -26,8 +26,7 @@ fill_pipeline_and_check (GstElement * comp, GList * segments, /* Expected segments */ collect->expected_segments = segments; - g_signal_connect (G_OBJECT (comp), "pad-added", - G_CALLBACK (composition_pad_added_cb), collect); + gst_element_link (comp, sink); sinkpad = gst_element_get_static_pad (sink, "sink"); gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM, @@ -562,8 +561,7 @@ GST_START_TEST (test_renegotiation) segment_new (1.0, GST_FORMAT_TIME, 2 * GST_SECOND, 3 * GST_SECOND, 2 * GST_SECOND)); - g_signal_connect (G_OBJECT (comp), "pad-added", - G_CALLBACK (composition_pad_added_cb), collect); + gst_element_link (comp, audioconvert); sinkpad = gst_element_get_static_pad (sink, "sink"); gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM, diff --git a/tests/check/gnl/gnlcomposition.c b/tests/check/gnl/gnlcomposition.c index 1710e2f..dab8ba3 100644 --- a/tests/check/gnl/gnlcomposition.c +++ b/tests/check/gnl/gnlcomposition.c @@ -24,12 +24,7 @@ typedef struct GstElement *source3; } TestClosure; -static int composition_pad_added; -static int composition_pad_removed; static int seek_events; -static gulong blockprobeid = 0; -static GMutex pad_added_lock; -static GCond pad_added_cond; static GstPadProbeReturn on_source1_pad_event_cb (GstPad * pad, GstPadProbeInfo * info, @@ -41,35 +36,9 @@ on_source1_pad_event_cb (GstPad * pad, GstPadProbeInfo * info, return GST_PAD_PROBE_OK; } -static void -on_source1_pad_added_cb (GstElement * source, GstPad * pad, gpointer user_data) -{ - gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, - (GstPadProbeCallback) on_source1_pad_event_cb, NULL, NULL); -} - -static void -on_composition_pad_added_cb (GstElement * composition, GstPad * pad, - GstElement * sink) -{ - GstPad *s = gst_element_get_static_pad (sink, "sink"); - gst_pad_link (pad, s); - ++composition_pad_added; - g_mutex_lock (&pad_added_lock); - g_cond_broadcast (&pad_added_cond); - g_mutex_unlock (&pad_added_lock); - gst_object_unref (s); -} - -static void -on_composition_pad_removed_cb (GstElement * composition, GstPad * pad, - GstElement * sink) -{ - ++composition_pad_removed; -} - GST_START_TEST (test_change_object_start_stop_in_current_stack) { + GstPad *srcpad; GstElement *pipeline; GstElement *comp, *source1, *def, *sink; GstBus *bus; @@ -84,11 +53,7 @@ GST_START_TEST (test_change_object_start_stop_in_current_stack) sink = gst_element_factory_make_or_warn ("fakesink", "sink"); gst_bin_add_many (GST_BIN (pipeline), comp, sink, NULL); - /* connect to pad-added */ - g_object_connect (comp, "signal::pad-added", - on_composition_pad_added_cb, sink, NULL); - g_object_connect (comp, "signal::pad-removed", - on_composition_pad_removed_cb, NULL, NULL); + gst_element_link (comp, sink); /* source1 @@ -98,8 +63,9 @@ GST_START_TEST (test_change_object_start_stop_in_current_stack) */ source1 = videotest_gnl_src ("source1", 0, 2 * GST_SECOND, 2, 2); - g_object_connect (source1, "signal::pad-added", - on_source1_pad_added_cb, NULL, NULL); + srcpad = gst_element_get_static_pad (source1, "src"); + gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, + (GstPadProbeCallback) on_source1_pad_event_cb, NULL, NULL); /* def (default source) @@ -161,9 +127,6 @@ GST_START_TEST (test_change_object_start_stop_in_current_stack) } } - fail_unless_equals_int (composition_pad_added, 1); - fail_unless_equals_int (composition_pad_removed, 0); - seek_events_before = seek_events; /* pipeline is paused at this point */ @@ -171,15 +134,13 @@ GST_START_TEST (test_change_object_start_stop_in_current_stack) /* move source1 out of the active segment */ g_object_set (source1, "start", (guint64) 4 * GST_SECOND, NULL); g_signal_emit_by_name (comp, "commit", TRUE, &ret); - fail_unless (seek_events > seek_events_before); + fail_unless (seek_events > seek_events_before, "%i > %i", seek_events, + seek_events_before); /* remove source1 from the composition, which will become empty and remove the * ghostpad */ gst_bin_remove (GST_BIN (comp), source1); - fail_unless_equals_int (composition_pad_added, 1); - fail_unless_equals_int (composition_pad_removed, 1); - g_object_set (source1, "start", (guint64) 0 * GST_SECOND, NULL); /* add the source again and check that the ghostpad is added again */ gst_bin_add (GST_BIN (comp), source1); @@ -234,177 +195,6 @@ GST_START_TEST (test_remove_invalid_object) GST_END_TEST; -static GstPadProbeReturn -pad_block (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) -{ - GstPad *ghost; - GstBin *bin; - - bin = GST_BIN (user_data); - - GST_DEBUG_OBJECT (pad, "probe type:0x%x", GST_PAD_PROBE_INFO_TYPE (info)); - - ghost = gst_ghost_pad_new ("src", pad); - gst_pad_set_active (ghost, TRUE); - - gst_element_add_pad (GST_ELEMENT (bin), ghost); - - return GST_PAD_PROBE_REMOVE; -} - -static void -no_more_pads_test_cb (GObject * object, TestClosure * c) -{ - gboolean ret; - - GST_WARNING ("NO MORE PADS"); - gst_bin_add (GST_BIN (c->composition), c->source3); - g_signal_emit_by_name (c->composition, "commit", TRUE, &ret); -} - -GST_START_TEST (test_no_more_pads_race) -{ - gboolean ret; - GstElement *source1, *source2, *source3; - GstBin *bin; - GstElement *videotestsrc1, *videotestsrc2; - GstElement *operation; - GstElement *composition; - GstElement *videomixer, *fakesink; - GstElement *pipeline; - GstBus *bus; - GstMessage *message; - GstPad *pad; - TestClosure closure; - - /* We create a composition with an operation and three sources. The operation - * contains a videomixer instance and the three sources are videotestsrc's. - * - * One of the sources, source2, contains videotestsrc inside a bin. Initially - * the bin doesn't have a source pad. We do this to exercise the dynamic src - * pad code path in gnlcomposition. We block on the videotestsrc srcpad and in - * the pad block callback we ghost the pad and add the ghost to the parent - * bin. This makes gnlsource emit no-more-pads, which is used by - * gnlcomposition to link the source2:src pad to videomixer. - * - * We start with the composition containing operation and source1. We preroll - * and then add source2. Source2 will do what described above and emit - * no-more-pads. We connect to that no-more-pads and from there we add source3 to - * the composition. Adding a new source will make gnlcomposition deactivate - * the old stack and activate a new one. The new one contains operation, - * source1, source2 and source3. Source2 was active in the old stack as well and - * gnlcomposition is *still waiting* for no-more-pads to be emitted on it - * (since the no-more-pads emission is now blocked in our test's no-more-pads - * callback, calling gst_bin_add). In short, here, we're simulating a race between - * no-more-pads and someone modifying the composition. - * - * Activating the new stack, gnlcomposition calls compare_relink_single_node, - * which finds an existing source pad for source2 this time since we have - * already blocked and ghosted. It takes another code path that assumes that - * source2 doesn't have dynamic pads and *BOOM*. - */ - - pipeline = GST_ELEMENT (gst_pipeline_new (NULL)); - bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); - - composition = gst_element_factory_make ("gnlcomposition", "composition"); - fakesink = gst_element_factory_make ("fakesink", NULL); - fail_unless (fakesink != NULL); - g_object_set (fakesink, "sync", TRUE, NULL); - - /* operation */ - operation = gst_element_factory_make ("gnloperation", "operation"); - videomixer = gst_element_factory_make ("videomixer", "videomixer"); - fail_unless (videomixer != NULL); - gst_bin_add (GST_BIN (operation), videomixer); - g_object_set (operation, "start", (guint64) 0 * GST_SECOND, - "duration", (guint64) 10 * GST_SECOND, - "inpoint", (guint64) 0 * GST_SECOND, "priority", 10, NULL); - gst_bin_add (GST_BIN (composition), operation); - - /* source 1 */ - source1 = gst_element_factory_make ("gnlsource", "source1"); - videotestsrc1 = gst_element_factory_make ("videotestsrc", "videotestsrc1"); - gst_bin_add (GST_BIN (source1), videotestsrc1); - g_object_set (source1, "start", (guint64) 0 * GST_SECOND, "duration", - (guint64) 5 * GST_SECOND, "inpoint", (guint64) 0 * GST_SECOND, "priority", - 20, NULL); - - /* source2 */ - source2 = gst_element_factory_make ("gnlsource", "source2"); - bin = GST_BIN (gst_bin_new (NULL)); - videotestsrc2 = gst_element_factory_make ("videotestsrc", "videotestsrc2"); - pad = gst_element_get_static_pad (videotestsrc2, "src"); - blockprobeid = - gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, - (GstPadProbeCallback) pad_block, bin, NULL); - gst_bin_add (bin, videotestsrc2); - gst_bin_add (GST_BIN (source2), GST_ELEMENT (bin)); - g_object_set (source2, "start", (guint64) 0 * GST_SECOND, "duration", - (guint64) 5 * GST_SECOND, "inpoint", (guint64) 0 * GST_SECOND, "priority", - 20, NULL); - - /* source3 */ - source3 = gst_element_factory_make ("gnlsource", "source3"); - videotestsrc2 = gst_element_factory_make ("videotestsrc", "videotestsrc3"); - gst_bin_add (GST_BIN (source3), videotestsrc2); - g_object_set (source3, "start", (guint64) 0 * GST_SECOND, "duration", - (guint64) 5 * GST_SECOND, "inpoint", (guint64) 0 * GST_SECOND, "priority", - 20, NULL); - - closure.composition = composition; - closure.source3 = source3; - g_object_connect (source2, "signal::no-more-pads", - no_more_pads_test_cb, &closure, NULL); - - gst_bin_add (GST_BIN (composition), source1); - g_signal_emit_by_name (composition, "commit", TRUE, &ret); - g_object_connect (composition, "signal::pad-added", - on_composition_pad_added_cb, fakesink, NULL); - g_object_connect (composition, "signal::pad-removed", - on_composition_pad_removed_cb, NULL, NULL); - - GST_DEBUG ("Adding composition to pipeline"); - - gst_bin_add_many (GST_BIN (pipeline), composition, fakesink, NULL); - - GST_DEBUG ("Setting pipeline to PAUSED"); - - fail_if (gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PAUSED) - == GST_STATE_CHANGE_FAILURE); - - message = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, - GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR); - if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR) { - fail_error_message (message); - } - gst_message_unref (message); - - GST_DEBUG ("Adding second source"); - - /* FIXME: maybe slow down the videotestsrc steaming thread */ - gst_bin_add (GST_BIN (composition), source2); - g_signal_emit_by_name (composition, "commit", TRUE, &ret); - - message = - gst_bus_timed_pop_filtered (bus, GST_SECOND / 10, GST_MESSAGE_ERROR); - if (message) { - if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR) { - fail_error_message (message); - } else { - fail_if (TRUE); - } - - gst_message_unref (message); - } - - gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); - gst_object_unref (pipeline); - gst_object_unref (bus); -} - -GST_END_TEST; - GST_START_TEST (test_simple_adder) { GstBus *bus; @@ -452,19 +242,13 @@ GST_START_TEST (test_simple_adder) g_object_set (gnlsource2, "start", (guint64) 0 * GST_SECOND, "duration", total_time, "inpoint", (guint64) 0 * GST_SECOND, "priority", 2, NULL); - fail_unless (gst_bin_add (GST_BIN (composition), gnlsource2)); - - /* Connecting signals */ - g_object_connect (composition, "signal::pad-added", - on_composition_pad_added_cb, fakesink, NULL); - g_object_connect (composition, "signal::pad-removed", - on_composition_pad_removed_cb, NULL, NULL); - GST_DEBUG ("Adding composition to pipeline"); - gst_bin_add_many (GST_BIN (pipeline), composition, fakesink, NULL); + fail_unless (gst_bin_add (GST_BIN (composition), gnlsource2)); + fail_unless (gst_element_link (composition, fakesink) == TRUE); + GST_DEBUG ("Setting pipeline to PAUSED"); g_signal_emit_by_name (composition, "commit", TRUE, &ret); @@ -536,16 +320,8 @@ gnonlin_suite (void) suite_add_tcase (s, tc_chain); - g_cond_init (&pad_added_cond); - g_mutex_init (&pad_added_lock); tcase_add_test (tc_chain, test_change_object_start_stop_in_current_stack); tcase_add_test (tc_chain, test_remove_invalid_object); - if (gst_registry_check_feature_version (gst_registry_get (), "videomixer", 0, - 11, 0)) { - tcase_add_test (tc_chain, test_no_more_pads_race); - } else { - GST_WARNING ("videomixer element not available, skipping 1 test"); - } if (gst_registry_check_feature_version (gst_registry_get (), "adder", 1, 0, 0)) { diff --git a/tests/check/gnl/gnloperation.c b/tests/check/gnl/gnloperation.c index d6f7a78..72d6e43 100644 --- a/tests/check/gnl/gnloperation.c +++ b/tests/check/gnl/gnloperation.c @@ -25,8 +25,7 @@ fill_pipeline_and_check (GstElement * comp, GList * segments) /* Expected segments */ collect->expected_segments = segments; - g_signal_connect (G_OBJECT (comp), "pad-added", - G_CALLBACK (composition_pad_added_cb), collect); + gst_element_link (comp, sink); sinkpad = gst_element_get_static_pad (sink, "sink"); gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM, diff --git a/tests/check/gnl/gnlsource.c b/tests/check/gnl/gnlsource.c index e2d568a..e10cc4b 100644 --- a/tests/check/gnl/gnlsource.c +++ b/tests/check/gnl/gnlsource.c @@ -39,8 +39,7 @@ GST_START_TEST (test_simple_videotestsrc) segment_new (1.0, GST_FORMAT_TIME, 1 * GST_SECOND, 2 * GST_SECOND, 1 * GST_SECOND)); - g_signal_connect (G_OBJECT (gnlsource), "pad-added", - G_CALLBACK (composition_pad_added_cb), collect); + gst_element_link (gnlsource, sink); sinkpad = gst_element_get_static_pad (sink, "sink"); fail_if (sinkpad == NULL); @@ -139,8 +138,7 @@ GST_START_TEST (test_videotestsrc_in_bin) collect->expected_segments = g_list_append (collect->expected_segments, segment_new (1.0, GST_FORMAT_TIME, 0, 1 * GST_SECOND, 0)); - g_signal_connect (G_OBJECT (gnlsource), "pad-added", - G_CALLBACK (composition_pad_added_cb), collect); + gst_element_link (gnlsource, sink); sinkpad = gst_element_get_static_pad (sink, "sink"); fail_if (sinkpad == NULL); diff --git a/tests/check/gnl/seek.c b/tests/check/gnl/seek.c index a3471d8..71240bf 100644 --- a/tests/check/gnl/seek.c +++ b/tests/check/gnl/seek.c @@ -1,4 +1,5 @@ #include "common.h" +static const gchar *compositor_element = NULL; typedef struct _SeekInfo { @@ -48,8 +49,7 @@ fill_pipeline_and_check (GstElement * comp, GList * segments, GList * seeks) collect->expected_segments = segments; collect->keep_expected_segments = TRUE; - g_signal_connect (G_OBJECT (comp), "pad-added", - G_CALLBACK (composition_pad_added_cb), collect); + gst_element_link (comp, sink); sinkpad = gst_element_get_static_pad (sink, "sink"); gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, @@ -521,7 +521,8 @@ GST_START_TEST (test_complex_operations) */ oper = - new_operation ("oper", "videomixer", 2 * GST_SECOND, 2 * GST_SECOND, 1); + new_operation ("oper", compositor_element, 2 * GST_SECOND, 2 * GST_SECOND, + 1); fail_if (oper == NULL); check_start_stop_duration (oper, 2 * GST_SECOND, 4 * GST_SECOND, 2 * GST_SECOND); @@ -639,7 +640,8 @@ GST_START_TEST (test_complex_operations_bis) */ oper = - new_operation ("oper", "videomixer", 2 * GST_SECOND, 2 * GST_SECOND, 1); + new_operation ("oper", compositor_element, 2 * GST_SECOND, 2 * GST_SECOND, + 1); fail_if (oper == NULL); check_start_stop_duration (oper, 2 * GST_SECOND, 4 * GST_SECOND, 2 * GST_SECOND); @@ -751,12 +753,26 @@ gnonlin_suite (void) suite_add_tcase (s, tc_chain); + if (gst_registry_check_feature_version (gst_registry_get (), "compositor", 1, + 0, 0)) { + compositor_element = "compositor"; + } else if (gst_registry_check_feature_version (gst_registry_get (), + "videomixer", 1, 0, 0)) { + compositor_element = "videomixer"; + + } + tcase_add_test (tc_chain, test_simplest); tcase_add_test (tc_chain, test_one_after_other); tcase_add_test (tc_chain, test_one_under_another); tcase_add_test (tc_chain, test_one_bin_after_other); - tcase_add_test (tc_chain, test_complex_operations); - tcase_add_test (tc_chain, test_complex_operations_bis); + + if (compositor_element) { + tcase_add_test (tc_chain, test_complex_operations); + tcase_add_test (tc_chain, test_complex_operations_bis); + } else { + GST_WARNING ("No compositor element, can not run operations tests"); + } return s; } diff --git a/tests/check/gnl/simple.c b/tests/check/gnl/simple.c index c305a6c..47800a1 100644 --- a/tests/check/gnl/simple.c +++ b/tests/check/gnl/simple.c @@ -52,9 +52,7 @@ test_simplest_full (void) collect->expected_segments = g_list_append (collect->expected_segments, segment_new (1.0, GST_FORMAT_TIME, 5 * GST_SECOND, 6 * GST_SECOND, 0)); - g_signal_connect (G_OBJECT (comp), "pad-added", - G_CALLBACK (composition_pad_added_cb), collect); - + gst_element_link (comp, sink); sinkpad = gst_element_get_static_pad (sink, "sink"); gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM, (GstPadProbeCallback) sinkpad_probe, collect, NULL); @@ -282,8 +280,7 @@ test_one_after_other_full (void) segment_new (1.0, GST_FORMAT_TIME, 2 * GST_SECOND, 3 * GST_SECOND, 1 * GST_SECOND)); - g_signal_connect (G_OBJECT (comp), "pad-added", - G_CALLBACK (composition_pad_added_cb), collect); + gst_element_link (comp, sink); sinkpad = gst_element_get_static_pad (sink, "sink"); gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM, @@ -485,8 +482,7 @@ test_one_under_another_full (void) segment_new (1.0, GST_FORMAT_TIME, 2 * GST_SECOND, 3 * GST_SECOND, 2 * GST_SECOND)); - g_signal_connect (G_OBJECT (comp), "pad-added", - G_CALLBACK (composition_pad_added_cb), collect); + gst_element_link (comp, sink); sinkpad = gst_element_get_static_pad (sink, "sink"); gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM, @@ -634,8 +630,7 @@ test_one_bin_after_other_full (void) segment_new (1.0, GST_FORMAT_TIME, 1 * GST_SECOND, 2 * GST_SECOND, 1 * GST_SECOND)); - g_signal_connect (G_OBJECT (comp), "pad-added", - G_CALLBACK (composition_pad_added_cb), collect); + gst_element_link (comp, sink); sinkpad = gst_element_get_static_pad (sink, "sink"); gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,