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);
gboolean flushing;
/* source top-level ghostpad, probe and entry */
- GstPad *ghostpad;
gulong ghosteventprobe;
GnlCompositionEntry *toplevelentry;
GstClockTime segment_start;
GstClockTime segment_stop;
- /* pending child seek */
- GstEvent *childseek;
-
/* Seek segment handler */
GstSegment *segment;
GstSegment *outside_segment;
/* 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
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);
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) \
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;
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);
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
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
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;
g_list_free (priv->expandables);
priv->expandables = NULL;
}
+ gnl_composition_reset_target_pad (comp);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
}
}
-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)
{
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;
}
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;
}
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);
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) {
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,
return TRUE;
}
-static void
+static gboolean
handle_seek_event (GnlComposition * comp, GstEvent * event)
{
gdouble rate;
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)
comp->priv->next_base_time = 0;
seek_handling (comp, TRUE, FALSE);
+ return TRUE;
}
static gboolean
{
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. */
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:
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)
{
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;
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");
}
}
-/*
- *
- * 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)
{
/* 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;
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));
}
}
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
*
*
* WITH OBJECTS LOCK TAKEN
*/
-
static void
compare_relink_single_node (GnlComposition * comp, GNode * node,
GNode * oldstack)
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)",
}
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);
}
/* 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)));
}
*
* WITH OBJECTS LOCK TAKEN
*/
-
static GList *
compare_deactivate_single_node (GnlComposition * comp, GNode * node,
GNode * newstack, gboolean modify)
GList *deactivate = NULL;
GnlObject *oldobj = NULL;
GstPad *srcpad = NULL;
+ GstPad *peerpad = NULL;
+ GnlCompositionEntry *entry;
if (G_UNLIKELY (!node))
return NULL;
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 */
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;
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));
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)));
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");
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);
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;
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,
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;
}
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)
{
/* ...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)))
goto out;
}
- if (entry->nomorepadshandler)
- wait_no_more_pads (comp, element, entry, FALSE);
gst_object_ref (element);
gst_element_set_locked_state (element, FALSE);
/* Make it possible to reuse the same object later */
gnl_object_reset (GNL_OBJECT (element));
gst_object_unref (element);
+
out:
return ret;
}
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,
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;
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
*/
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)
}
}
- 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 */
/* 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);
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;
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);
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)) {