mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 10:11:08 +00:00
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
This commit is contained in:
parent
38b080deb3
commit
4cb834fa21
14 changed files with 438 additions and 967 deletions
File diff suppressed because it is too large
Load diff
|
@ -35,6 +35,8 @@ struct _GnlPadPrivate
|
||||||
GstPadDirection dir;
|
GstPadDirection dir;
|
||||||
GstPadEventFunction eventfunc;
|
GstPadEventFunction eventfunc;
|
||||||
GstPadQueryFunction queryfunc;
|
GstPadQueryFunction queryfunc;
|
||||||
|
|
||||||
|
GstEvent *pending_seek;
|
||||||
};
|
};
|
||||||
|
|
||||||
static GstEvent *
|
static GstEvent *
|
||||||
|
@ -489,7 +491,18 @@ ghostpad_event_function (GstPad * ghostpad, GstObject * parent,
|
||||||
{
|
{
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_SEEK:
|
case GST_EVENT_SEEK:
|
||||||
|
{
|
||||||
|
GstPad *target;
|
||||||
|
|
||||||
event = translate_incoming_seek (object, event);
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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 (target, FALSE);
|
||||||
g_return_val_if_fail ((dir != GST_PAD_UNKNOWN), 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) {
|
if (!ghost) {
|
||||||
GST_WARNING_OBJECT (object, "Couldn't create ghostpad");
|
GST_WARNING_OBJECT (object, "Couldn't create ghostpad");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -692,17 +705,19 @@ gnl_object_ghost_pad (GnlObject * object, const gchar * name, GstPad * target)
|
||||||
*/
|
*/
|
||||||
GstPad *
|
GstPad *
|
||||||
gnl_object_ghost_pad_no_target (GnlObject * object, const gchar * name,
|
gnl_object_ghost_pad_no_target (GnlObject * object, const gchar * name,
|
||||||
GstPadDirection dir)
|
GstPadDirection dir, GstPadTemplate * template)
|
||||||
{
|
{
|
||||||
GstPad *ghost;
|
GstPad *ghost;
|
||||||
GnlPadPrivate *priv;
|
GnlPadPrivate *priv;
|
||||||
|
|
||||||
/* create a no_target ghostpad */
|
/* 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)
|
if (!ghost)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
GST_DEBUG ("grabbing existing pad functions");
|
|
||||||
|
|
||||||
/* remember the existing ghostpad event/query/link/unlink functions */
|
/* remember the existing ghostpad event/query/link/unlink functions */
|
||||||
priv = g_slice_new0 (GnlPadPrivate);
|
priv = g_slice_new0 (GnlPadPrivate);
|
||||||
|
@ -726,6 +741,8 @@ gnl_object_ghost_pad_no_target (GnlObject * object, const gchar * name,
|
||||||
return ghost;
|
return ghost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
gnl_object_remove_ghost_pad (GnlObject * object, GstPad * ghost)
|
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);
|
GnlPadPrivate *priv = gst_pad_get_element_private (ghost);
|
||||||
|
|
||||||
g_return_val_if_fail (priv, FALSE);
|
g_return_val_if_fail (priv, FALSE);
|
||||||
|
g_return_val_if_fail (GST_IS_PAD (ghost), FALSE);
|
||||||
|
|
||||||
if (target)
|
if (target) {
|
||||||
GST_DEBUG_OBJECT (object, "setting target %s:%s on ghostpad",
|
GST_DEBUG_OBJECT (object, "setting target %s:%s on %s:%s",
|
||||||
GST_DEBUG_PAD_NAME (target));
|
GST_DEBUG_PAD_NAME (target), GST_DEBUG_PAD_NAME (ghost));
|
||||||
else
|
} else {
|
||||||
GST_DEBUG_OBJECT (object, "removing target from ghostpad");
|
GST_ERROR_OBJECT (object, "removing target from ghostpad");
|
||||||
|
priv->pending_seek = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* set target */
|
/* 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;
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ GstPad *gnl_object_ghost_pad (GnlObject * object,
|
||||||
const gchar * name, GstPad * target);
|
const gchar * name, GstPad * target);
|
||||||
|
|
||||||
GstPad *gnl_object_ghost_pad_no_target (GnlObject * object,
|
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,
|
gboolean gnl_object_ghost_pad_set_target (GnlObject * object,
|
||||||
GstPad * ghost, GstPad * target);
|
GstPad * ghost, GstPad * target);
|
||||||
|
|
|
@ -42,10 +42,7 @@
|
||||||
GST_DEBUG_CATEGORY_STATIC (gnlobject_debug);
|
GST_DEBUG_CATEGORY_STATIC (gnlobject_debug);
|
||||||
#define GST_CAT_DEFAULT gnlobject_debug
|
#define GST_CAT_DEFAULT gnlobject_debug
|
||||||
|
|
||||||
#define _do_init \
|
static GObjectClass *parent_class = NULL;
|
||||||
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);
|
|
||||||
|
|
||||||
/****************************************************
|
/****************************************************
|
||||||
* Helper macros *
|
* Helper macros *
|
||||||
|
@ -117,6 +114,9 @@ gnl_object_class_init (GnlObjectClass * klass)
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
gstelement_class = (GstElementClass *) klass;
|
gstelement_class = (GstElementClass *) klass;
|
||||||
gnlobject_class = (GnlObjectClass *) 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->set_property = GST_DEBUG_FUNCPTR (gnl_object_set_property);
|
||||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gnl_object_get_property);
|
gobject_class->get_property = GST_DEBUG_FUNCPTR (gnl_object_get_property);
|
||||||
|
@ -243,7 +243,7 @@ gnl_object_class_init (GnlObjectClass * klass)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gnl_object_init (GnlObject * object)
|
gnl_object_init (GnlObject * object, GnlObjectClass * klass)
|
||||||
{
|
{
|
||||||
object->start = object->pending_start = 0;
|
object->start = object->pending_start = 0;
|
||||||
object->duration = object->pending_duration = 0;
|
object->duration = object->pending_duration = 0;
|
||||||
|
@ -258,6 +258,12 @@ gnl_object_init (GnlObject * object)
|
||||||
object->segment_rate = 1.0;
|
object->segment_rate = 1.0;
|
||||||
object->segment_start = -1;
|
object->segment_start = -1;
|
||||||
object->segment_stop = -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
|
static void
|
||||||
|
@ -653,3 +659,30 @@ gnl_object_reset (GnlObject * object)
|
||||||
object->priority = 0;
|
object->priority = 0;
|
||||||
object->active = TRUE;
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -43,6 +43,8 @@ G_BEGIN_DECLS
|
||||||
#define GNL_IS_OBJECT_CLASS(obj) \
|
#define GNL_IS_OBJECT_CLASS(obj) \
|
||||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GNL_TYPE_OBJECT))
|
(G_TYPE_CHECK_CLASS_TYPE((klass),GNL_TYPE_OBJECT))
|
||||||
|
|
||||||
|
#define GNL_OBJECT_SRC(obj) (((GnlObject *) obj)->srcpad)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GnlObjectFlags:
|
* GnlObjectFlags:
|
||||||
* @GNL_OBJECT_IS_SOURCE:
|
* @GNL_OBJECT_IS_SOURCE:
|
||||||
|
@ -84,6 +86,8 @@ struct _GnlObject
|
||||||
{
|
{
|
||||||
GstBin parent;
|
GstBin parent;
|
||||||
|
|
||||||
|
GstPad *srcpad;
|
||||||
|
|
||||||
/* Time positionning */
|
/* Time positionning */
|
||||||
GstClockTime start;
|
GstClockTime start;
|
||||||
GstClockTime inpoint;
|
GstClockTime inpoint;
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
static GstStaticPadTemplate gnl_operation_src_template =
|
static GstStaticPadTemplate gnl_operation_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_SOMETIMES,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS_ANY);
|
GST_STATIC_CAPS_ANY);
|
||||||
|
|
||||||
static GstStaticPadTemplate gnl_operation_sink_template =
|
static GstStaticPadTemplate gnl_operation_sink_template =
|
||||||
|
@ -163,10 +163,9 @@ gnl_operation_dispose (GObject * object)
|
||||||
GnlOperation *oper = (GnlOperation *) object;
|
GnlOperation *oper = (GnlOperation *) object;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (object, "Disposing of source pad");
|
GST_DEBUG_OBJECT (object, "Disposing of source pad");
|
||||||
if (oper->ghostpad) {
|
|
||||||
gnl_object_remove_ghost_pad (GNL_OBJECT (oper), oper->ghostpad);
|
gnl_object_ghost_pad_set_target (GNL_OBJECT (object),
|
||||||
oper->ghostpad = NULL;
|
GNL_OBJECT (object)->srcpad, NULL);
|
||||||
}
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (object, "Disposing of sink pad(s)");
|
GST_DEBUG_OBJECT (object, "Disposing of sink pad(s)");
|
||||||
while (oper->sinks) {
|
while (oper->sinks) {
|
||||||
|
@ -190,7 +189,6 @@ static void
|
||||||
gnl_operation_init (GnlOperation * operation)
|
gnl_operation_init (GnlOperation * operation)
|
||||||
{
|
{
|
||||||
gnl_operation_reset (operation);
|
gnl_operation_reset (operation);
|
||||||
operation->ghostpad = NULL;
|
|
||||||
operation->element = NULL;
|
operation->element = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,13 +360,8 @@ gnl_operation_add_element (GstBin * bin, GstElement * element)
|
||||||
operation->element = element;
|
operation->element = element;
|
||||||
operation->dynamicsinks = isdynamic;
|
operation->dynamicsinks = isdynamic;
|
||||||
|
|
||||||
/* Source ghostpad */
|
gnl_object_ghost_pad_set_target (GNL_OBJECT (operation),
|
||||||
if (operation->ghostpad)
|
GNL_OBJECT (operation)->srcpad, srcpad);
|
||||||
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);
|
|
||||||
|
|
||||||
/* Remove the reference get_src_pad gave us */
|
/* Remove the reference get_src_pad gave us */
|
||||||
gst_object_unref (srcpad);
|
gst_object_unref (srcpad);
|
||||||
|
|
|
@ -59,8 +59,6 @@ G_BEGIN_DECLS
|
||||||
/* FIXME : We might need to use a lock to access this list */
|
/* FIXME : We might need to use a lock to access this list */
|
||||||
GList * sinks; /* The sink ghostpads */
|
GList * sinks; /* The sink ghostpads */
|
||||||
|
|
||||||
GstPad *ghostpad; /* src ghostpad */
|
|
||||||
|
|
||||||
GstElement *element; /* controlled element */
|
GstElement *element; /* controlled element */
|
||||||
|
|
||||||
GstClockTime next_base_time;
|
GstClockTime next_base_time;
|
||||||
|
|
108
gnl/gnlsource.c
108
gnl/gnlsource.c
|
@ -35,7 +35,7 @@
|
||||||
static GstStaticPadTemplate gnl_source_src_template =
|
static GstStaticPadTemplate gnl_source_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_SOMETIMES,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS_ANY);
|
GST_STATIC_CAPS_ANY);
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_STATIC (gnlsource);
|
GST_DEBUG_CATEGORY_STATIC (gnlsource);
|
||||||
|
@ -51,7 +51,6 @@ struct _GnlSourcePrivate
|
||||||
gboolean dispose_has_run;
|
gboolean dispose_has_run;
|
||||||
|
|
||||||
gboolean dynamicpads; /* TRUE if the controlled element has dynamic pads */
|
gboolean dynamicpads; /* TRUE if the controlled element has dynamic pads */
|
||||||
GstPad *ghostpad; /* The source ghostpad */
|
|
||||||
GstEvent *event; /* queued event */
|
GstEvent *event; /* queued event */
|
||||||
|
|
||||||
gulong padremovedid; /* signal handler for element pad-removed signal */
|
gulong padremovedid; /* signal handler for element pad-removed signal */
|
||||||
|
@ -59,9 +58,10 @@ struct _GnlSourcePrivate
|
||||||
gulong probeid; /* source pad probe id */
|
gulong probeid; /* source pad probe id */
|
||||||
|
|
||||||
gboolean pendingblock; /* We have a pending pad_block */
|
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 *ghostedpad; /* Pad (to be) ghosted */
|
||||||
GstPad *staticpad; /* The only pad. We keep an extra ref */
|
GstPad *staticpad; /* The only pad. We keep an extra ref */
|
||||||
|
gboolean got_seeked;
|
||||||
};
|
};
|
||||||
|
|
||||||
static gboolean gnl_source_prepare (GnlObject * object);
|
static gboolean gnl_source_prepare (GnlObject * object);
|
||||||
|
@ -136,6 +136,7 @@ gnl_source_init (GnlSource * source)
|
||||||
static void
|
static void
|
||||||
gnl_source_dispose (GObject * object)
|
gnl_source_dispose (GObject * object)
|
||||||
{
|
{
|
||||||
|
GnlObject *gnlobject = (GnlObject *) object;
|
||||||
GnlSource *source = (GnlSource *) object;
|
GnlSource *source = (GnlSource *) object;
|
||||||
GnlSourcePrivate *priv = source->priv;
|
GnlSourcePrivate *priv = source->priv;
|
||||||
|
|
||||||
|
@ -153,9 +154,8 @@ gnl_source_dispose (GObject * object)
|
||||||
if (priv->event)
|
if (priv->event)
|
||||||
gst_event_unref (priv->event);
|
gst_event_unref (priv->event);
|
||||||
|
|
||||||
if (priv->ghostpad)
|
if (priv->ghostedpad)
|
||||||
gnl_object_remove_ghost_pad ((GnlObject *) object, priv->ghostpad);
|
gnl_object_ghost_pad_set_target (gnlobject, gnlobject->srcpad, NULL);
|
||||||
priv->ghostpad = NULL;
|
|
||||||
|
|
||||||
if (priv->staticpad) {
|
if (priv->staticpad) {
|
||||||
gst_object_unref (priv->staticpad);
|
gst_object_unref (priv->staticpad);
|
||||||
|
@ -171,19 +171,20 @@ element_pad_added_cb (GstElement * element G_GNUC_UNUSED, GstPad * pad,
|
||||||
{
|
{
|
||||||
GstCaps *srccaps;
|
GstCaps *srccaps;
|
||||||
GnlSourcePrivate *priv = source->priv;
|
GnlSourcePrivate *priv = source->priv;
|
||||||
|
GnlObject *gnlobject = (GnlObject *) source;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (source, "pad %s:%s", GST_DEBUG_PAD_NAME (pad));
|
GST_DEBUG_OBJECT (source, "pad %s:%s", GST_DEBUG_PAD_NAME (pad));
|
||||||
|
|
||||||
if (priv->ghostpad || priv->pendingblock) {
|
if (priv->pendingblock) {
|
||||||
GST_WARNING_OBJECT (source,
|
GST_WARNING_OBJECT (source,
|
||||||
"We already have (pending) ghost-ed a valid source pad (ghostpad:%s:%s, pendingblock:%d",
|
"We already have (pending) ghost-ed a valid source pad (srcpad:%s:%s, pendingblock:%d",
|
||||||
GST_DEBUG_PAD_NAME (priv->ghostpad), priv->pendingblock);
|
GST_DEBUG_PAD_NAME (gnlobject->srcpad), priv->pendingblock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: pass filter caps to query_caps directly */
|
/* FIXME: pass filter caps to query_caps directly */
|
||||||
srccaps = gst_pad_query_caps (pad, NULL);
|
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_caps_unref (srccaps);
|
||||||
GST_DEBUG_OBJECT (source, "Pad doesn't have valid caps, ignoring");
|
GST_DEBUG_OBJECT (source, "Pad doesn't have valid caps, ignoring");
|
||||||
return;
|
return;
|
||||||
|
@ -210,6 +211,7 @@ element_pad_removed_cb (GstElement * element G_GNUC_UNUSED, GstPad * pad,
|
||||||
GnlSource * source)
|
GnlSource * source)
|
||||||
{
|
{
|
||||||
GnlSourcePrivate *priv = source->priv;
|
GnlSourcePrivate *priv = source->priv;
|
||||||
|
GnlObject *gnlobject = (GnlObject *) source;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (source, "pad %s:%s (controlled pad %s:%s)",
|
GST_DEBUG_OBJECT (source, "pad %s:%s (controlled pad %s:%s)",
|
||||||
GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (priv->ghostedpad));
|
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,
|
GST_DEBUG_OBJECT (source,
|
||||||
"The removed pad is the controlled pad, clearing up");
|
"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;
|
priv->is_blocked = FALSE;
|
||||||
if (priv->probeid) {
|
if (priv->probeid) {
|
||||||
gst_pad_remove_probe (pad, priv->probeid);
|
gst_pad_remove_probe (pad, priv->probeid);
|
||||||
priv->probeid = 0;
|
priv->probeid = 0;
|
||||||
}
|
|
||||||
|
|
||||||
gnl_object_remove_ghost_pad ((GnlObject *) source, priv->ghostpad);
|
|
||||||
priv->ghostpad = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gnl_object_ghost_pad_set_target (GNL_OBJECT (source), gnlobject->srcpad,
|
||||||
|
NULL);
|
||||||
|
|
||||||
priv->pendingblock = FALSE;
|
priv->pendingblock = FALSE;
|
||||||
priv->ghostedpad = NULL;
|
priv->ghostedpad = NULL;
|
||||||
} else {
|
} else {
|
||||||
|
@ -292,20 +292,24 @@ ghost_seek_pad (GnlSource * source)
|
||||||
{
|
{
|
||||||
GnlSourcePrivate *priv = source->priv;
|
GnlSourcePrivate *priv = source->priv;
|
||||||
GstPad *pad = priv->ghostedpad;
|
GstPad *pad = priv->ghostedpad;
|
||||||
|
GnlObject *gnlobject = (GnlObject *) source;
|
||||||
|
|
||||||
if (priv->ghostpad || !pad)
|
priv->got_seeked = TRUE;
|
||||||
|
|
||||||
|
if (!pad)
|
||||||
goto beach;
|
goto beach;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (source, "ghosting %s:%s", GST_DEBUG_PAD_NAME (pad));
|
GST_DEBUG_OBJECT (source, "ghosting %s:%s", GST_DEBUG_PAD_NAME (pad));
|
||||||
|
|
||||||
priv->ghostpad = gnl_object_ghost_pad ((GnlObject *) source,
|
gnl_object_ghost_pad_set_target (gnlobject, gnlobject->srcpad, pad);
|
||||||
GST_PAD_NAME (pad), pad);
|
|
||||||
GST_DEBUG_OBJECT (source, "emitting no more pads");
|
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) {
|
if (priv->event) {
|
||||||
GST_DEBUG_OBJECT (source, "sending queued seek 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,
|
GST_ELEMENT_ERROR (source, RESOURCE, SEEK,
|
||||||
(NULL), ("Sending initial seek to upstream element failed"));
|
(NULL), ("Sending initial seek to upstream element failed"));
|
||||||
else
|
else
|
||||||
|
@ -314,7 +318,7 @@ ghost_seek_pad (GnlSource * source)
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (source, "about to unblock %s:%s", GST_DEBUG_PAD_NAME (pad));
|
GST_DEBUG_OBJECT (source, "about to unblock %s:%s", GST_DEBUG_PAD_NAME (pad));
|
||||||
priv->areblocked = FALSE;
|
priv->is_blocked = FALSE;
|
||||||
if (priv->probeid) {
|
if (priv->probeid) {
|
||||||
gst_pad_remove_probe (pad, priv->probeid);
|
gst_pad_remove_probe (pad, priv->probeid);
|
||||||
priv->probeid = 0;
|
priv->probeid = 0;
|
||||||
|
@ -332,10 +336,10 @@ pad_blocked_cb (GstPad * pad, GstPadProbeInfo * info, GnlSource * source)
|
||||||
{
|
{
|
||||||
GST_DEBUG_OBJECT (pad, "probe callback");
|
GST_DEBUG_OBJECT (pad, "probe callback");
|
||||||
|
|
||||||
if (!source->priv->ghostpad && !source->priv->areblocked) {
|
if (!source->priv->got_seeked && !source->priv->is_blocked) {
|
||||||
GThread *lthread;
|
GThread *lthread;
|
||||||
|
|
||||||
source->priv->areblocked = TRUE;
|
source->priv->is_blocked = TRUE;
|
||||||
GST_DEBUG_OBJECT (pad, "starting thread to call ghost_seek_pad");
|
GST_DEBUG_OBJECT (pad, "starting thread to call ghost_seek_pad");
|
||||||
lthread =
|
lthread =
|
||||||
g_thread_new ("gnlsourceseek", (GThreadFunc) ghost_seek_pad, source);
|
g_thread_new ("gnlsourceseek", (GThreadFunc) ghost_seek_pad, source);
|
||||||
|
@ -439,6 +443,7 @@ static gboolean
|
||||||
gnl_source_remove_element (GstBin * bin, GstElement * element)
|
gnl_source_remove_element (GstBin * bin, GstElement * element)
|
||||||
{
|
{
|
||||||
GnlSource *source = (GnlSource *) bin;
|
GnlSource *source = (GnlSource *) bin;
|
||||||
|
GnlObject *gnlobject = (GnlObject *) element;
|
||||||
GnlSourcePrivate *priv = source->priv;
|
GnlSourcePrivate *priv = source->priv;
|
||||||
gboolean pret;
|
gboolean pret;
|
||||||
|
|
||||||
|
@ -452,11 +457,9 @@ gnl_source_remove_element (GstBin * bin, GstElement * element)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pret) {
|
if (pret) {
|
||||||
/* remove ghostpad */
|
gnl_object_ghost_pad_set_target (GNL_OBJECT (source), gnlobject->srcpad,
|
||||||
if (priv->ghostpad) {
|
NULL);
|
||||||
gnl_object_remove_ghost_pad ((GnlObject *) bin, priv->ghostpad);
|
priv->got_seeked = FALSE;
|
||||||
priv->ghostpad = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* discard events */
|
/* discard events */
|
||||||
if (priv->event) {
|
if (priv->event) {
|
||||||
|
@ -485,12 +488,13 @@ static gboolean
|
||||||
gnl_source_send_event (GstElement * element, GstEvent * event)
|
gnl_source_send_event (GstElement * element, GstEvent * event)
|
||||||
{
|
{
|
||||||
GnlSource *source = (GnlSource *) element;
|
GnlSource *source = (GnlSource *) element;
|
||||||
|
GnlObject *gnlobject = (GnlObject *) element;
|
||||||
gboolean res = TRUE;
|
gboolean res = TRUE;
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_SEEK:
|
case GST_EVENT_SEEK:
|
||||||
if (source->priv->ghostpad)
|
if (source->priv->ghostedpad)
|
||||||
res = gst_pad_send_event (source->priv->ghostpad, event);
|
res = gst_pad_send_event (gnlobject->srcpad, event);
|
||||||
else {
|
else {
|
||||||
if (source->priv->event)
|
if (source->priv->event)
|
||||||
gst_event_unref (source->priv->event);
|
gst_event_unref (source->priv->event);
|
||||||
|
@ -516,13 +520,15 @@ gnl_source_prepare (GnlObject * object)
|
||||||
if (!source->element) {
|
if (!source->element) {
|
||||||
GST_WARNING_OBJECT (source,
|
GST_WARNING_OBJECT (source,
|
||||||
"GnlSource doesn't have an element to control !");
|
"GnlSource doesn't have an element to control !");
|
||||||
|
if (parent)
|
||||||
|
gst_object_unref (parent);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_LOG_OBJECT (source, "ghostpad:%p, dynamicpads:%d",
|
GST_LOG_OBJECT (source, "srcpad:%p, dynamicpads:%d",
|
||||||
priv->ghostpad, priv->dynamicpads);
|
object->srcpad, priv->dynamicpads);
|
||||||
|
|
||||||
if (!(priv->ghostpad) && !priv->pendingblock) {
|
if (!(priv->got_seeked) && !priv->pendingblock) {
|
||||||
GstPad *pad;
|
GstPad *pad;
|
||||||
|
|
||||||
GST_LOG_OBJECT (source, "no ghostpad and no dynamic pads");
|
GST_LOG_OBJECT (source, "no ghostpad and no dynamic pads");
|
||||||
|
@ -568,22 +574,22 @@ gnl_source_cleanup (GnlObject * object)
|
||||||
GnlSource *source = GNL_SOURCE (object);
|
GnlSource *source = GNL_SOURCE (object);
|
||||||
GnlSourcePrivate *priv = source->priv;
|
GnlSourcePrivate *priv = source->priv;
|
||||||
|
|
||||||
if (priv->ghostpad) {
|
/* FIXME : should just be ghostedpad */
|
||||||
GstPad *target = gst_ghost_pad_get_target ((GstGhostPad *) priv->ghostpad);
|
GstPad *target = gst_ghost_pad_get_target ((GstGhostPad *) object->srcpad);
|
||||||
|
|
||||||
if (target) {
|
if (target) {
|
||||||
if (priv->probeid) {
|
if (priv->probeid) {
|
||||||
gst_pad_remove_probe (target, priv->probeid);
|
gst_pad_remove_probe (target, priv->probeid);
|
||||||
priv->probeid = 0;
|
priv->probeid = 0;
|
||||||
}
|
|
||||||
gst_object_unref (target);
|
|
||||||
}
|
}
|
||||||
gnl_object_remove_ghost_pad ((GnlObject *) source, priv->ghostpad);
|
gst_object_unref (target);
|
||||||
priv->ghostpad = NULL;
|
|
||||||
priv->ghostedpad = NULL;
|
|
||||||
priv->areblocked = FALSE;
|
|
||||||
priv->pendingblock = FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,7 @@ fill_pipeline_and_check (GstElement * comp, GList * segments,
|
||||||
/* Expected segments */
|
/* Expected segments */
|
||||||
collect->expected_segments = segments;
|
collect->expected_segments = segments;
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (comp), "pad-added",
|
gst_element_link (comp, sink);
|
||||||
G_CALLBACK (composition_pad_added_cb), collect);
|
|
||||||
|
|
||||||
sinkpad = gst_element_get_static_pad (sink, "sink");
|
sinkpad = gst_element_get_static_pad (sink, "sink");
|
||||||
gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
|
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,
|
segment_new (1.0, GST_FORMAT_TIME,
|
||||||
2 * GST_SECOND, 3 * GST_SECOND, 2 * GST_SECOND));
|
2 * GST_SECOND, 3 * GST_SECOND, 2 * GST_SECOND));
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (comp), "pad-added",
|
gst_element_link (comp, audioconvert);
|
||||||
G_CALLBACK (composition_pad_added_cb), collect);
|
|
||||||
|
|
||||||
sinkpad = gst_element_get_static_pad (sink, "sink");
|
sinkpad = gst_element_get_static_pad (sink, "sink");
|
||||||
gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
|
gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
|
||||||
|
|
|
@ -24,12 +24,7 @@ typedef struct
|
||||||
GstElement *source3;
|
GstElement *source3;
|
||||||
} TestClosure;
|
} TestClosure;
|
||||||
|
|
||||||
static int composition_pad_added;
|
|
||||||
static int composition_pad_removed;
|
|
||||||
static int seek_events;
|
static int seek_events;
|
||||||
static gulong blockprobeid = 0;
|
|
||||||
static GMutex pad_added_lock;
|
|
||||||
static GCond pad_added_cond;
|
|
||||||
|
|
||||||
static GstPadProbeReturn
|
static GstPadProbeReturn
|
||||||
on_source1_pad_event_cb (GstPad * pad, GstPadProbeInfo * info,
|
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;
|
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)
|
GST_START_TEST (test_change_object_start_stop_in_current_stack)
|
||||||
{
|
{
|
||||||
|
GstPad *srcpad;
|
||||||
GstElement *pipeline;
|
GstElement *pipeline;
|
||||||
GstElement *comp, *source1, *def, *sink;
|
GstElement *comp, *source1, *def, *sink;
|
||||||
GstBus *bus;
|
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");
|
sink = gst_element_factory_make_or_warn ("fakesink", "sink");
|
||||||
gst_bin_add_many (GST_BIN (pipeline), comp, sink, NULL);
|
gst_bin_add_many (GST_BIN (pipeline), comp, sink, NULL);
|
||||||
|
|
||||||
/* connect to pad-added */
|
gst_element_link (comp, sink);
|
||||||
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);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
source1
|
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);
|
source1 = videotest_gnl_src ("source1", 0, 2 * GST_SECOND, 2, 2);
|
||||||
g_object_connect (source1, "signal::pad-added",
|
srcpad = gst_element_get_static_pad (source1, "src");
|
||||||
on_source1_pad_added_cb, NULL, NULL);
|
gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM,
|
||||||
|
(GstPadProbeCallback) on_source1_pad_event_cb, NULL, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
def (default source)
|
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;
|
seek_events_before = seek_events;
|
||||||
|
|
||||||
/* pipeline is paused at this point */
|
/* 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 */
|
/* move source1 out of the active segment */
|
||||||
g_object_set (source1, "start", (guint64) 4 * GST_SECOND, NULL);
|
g_object_set (source1, "start", (guint64) 4 * GST_SECOND, NULL);
|
||||||
g_signal_emit_by_name (comp, "commit", TRUE, &ret);
|
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
|
/* remove source1 from the composition, which will become empty and remove the
|
||||||
* ghostpad */
|
* ghostpad */
|
||||||
gst_bin_remove (GST_BIN (comp), source1);
|
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);
|
g_object_set (source1, "start", (guint64) 0 * GST_SECOND, NULL);
|
||||||
/* add the source again and check that the ghostpad is added again */
|
/* add the source again and check that the ghostpad is added again */
|
||||||
gst_bin_add (GST_BIN (comp), source1);
|
gst_bin_add (GST_BIN (comp), source1);
|
||||||
|
@ -234,177 +195,6 @@ GST_START_TEST (test_remove_invalid_object)
|
||||||
|
|
||||||
GST_END_TEST;
|
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)
|
GST_START_TEST (test_simple_adder)
|
||||||
{
|
{
|
||||||
GstBus *bus;
|
GstBus *bus;
|
||||||
|
@ -452,19 +242,13 @@ GST_START_TEST (test_simple_adder)
|
||||||
g_object_set (gnlsource2, "start", (guint64) 0 * GST_SECOND,
|
g_object_set (gnlsource2, "start", (guint64) 0 * GST_SECOND,
|
||||||
"duration", total_time, "inpoint", (guint64) 0 * GST_SECOND, "priority",
|
"duration", total_time, "inpoint", (guint64) 0 * GST_SECOND, "priority",
|
||||||
2, NULL);
|
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_DEBUG ("Adding composition to pipeline");
|
||||||
|
|
||||||
gst_bin_add_many (GST_BIN (pipeline), composition, fakesink, NULL);
|
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");
|
GST_DEBUG ("Setting pipeline to PAUSED");
|
||||||
|
|
||||||
g_signal_emit_by_name (composition, "commit", TRUE, &ret);
|
g_signal_emit_by_name (composition, "commit", TRUE, &ret);
|
||||||
|
@ -536,16 +320,8 @@ gnonlin_suite (void)
|
||||||
|
|
||||||
suite_add_tcase (s, tc_chain);
|
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_change_object_start_stop_in_current_stack);
|
||||||
tcase_add_test (tc_chain, test_remove_invalid_object);
|
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,
|
if (gst_registry_check_feature_version (gst_registry_get (), "adder", 1,
|
||||||
0, 0)) {
|
0, 0)) {
|
||||||
|
|
|
@ -25,8 +25,7 @@ fill_pipeline_and_check (GstElement * comp, GList * segments)
|
||||||
/* Expected segments */
|
/* Expected segments */
|
||||||
collect->expected_segments = segments;
|
collect->expected_segments = segments;
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (comp), "pad-added",
|
gst_element_link (comp, sink);
|
||||||
G_CALLBACK (composition_pad_added_cb), collect);
|
|
||||||
|
|
||||||
sinkpad = gst_element_get_static_pad (sink, "sink");
|
sinkpad = gst_element_get_static_pad (sink, "sink");
|
||||||
gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
|
gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
|
||||||
|
|
|
@ -39,8 +39,7 @@ GST_START_TEST (test_simple_videotestsrc)
|
||||||
segment_new (1.0, GST_FORMAT_TIME,
|
segment_new (1.0, GST_FORMAT_TIME,
|
||||||
1 * GST_SECOND, 2 * GST_SECOND, 1 * GST_SECOND));
|
1 * GST_SECOND, 2 * GST_SECOND, 1 * GST_SECOND));
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (gnlsource), "pad-added",
|
gst_element_link (gnlsource, sink);
|
||||||
G_CALLBACK (composition_pad_added_cb), collect);
|
|
||||||
|
|
||||||
sinkpad = gst_element_get_static_pad (sink, "sink");
|
sinkpad = gst_element_get_static_pad (sink, "sink");
|
||||||
fail_if (sinkpad == NULL);
|
fail_if (sinkpad == NULL);
|
||||||
|
@ -139,8 +138,7 @@ GST_START_TEST (test_videotestsrc_in_bin)
|
||||||
collect->expected_segments = g_list_append (collect->expected_segments,
|
collect->expected_segments = g_list_append (collect->expected_segments,
|
||||||
segment_new (1.0, GST_FORMAT_TIME, 0, 1 * GST_SECOND, 0));
|
segment_new (1.0, GST_FORMAT_TIME, 0, 1 * GST_SECOND, 0));
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (gnlsource), "pad-added",
|
gst_element_link (gnlsource, sink);
|
||||||
G_CALLBACK (composition_pad_added_cb), collect);
|
|
||||||
|
|
||||||
sinkpad = gst_element_get_static_pad (sink, "sink");
|
sinkpad = gst_element_get_static_pad (sink, "sink");
|
||||||
fail_if (sinkpad == NULL);
|
fail_if (sinkpad == NULL);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
static const gchar *compositor_element = NULL;
|
||||||
|
|
||||||
typedef struct _SeekInfo
|
typedef struct _SeekInfo
|
||||||
{
|
{
|
||||||
|
@ -48,8 +49,7 @@ fill_pipeline_and_check (GstElement * comp, GList * segments, GList * seeks)
|
||||||
collect->expected_segments = segments;
|
collect->expected_segments = segments;
|
||||||
collect->keep_expected_segments = TRUE;
|
collect->keep_expected_segments = TRUE;
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (comp), "pad-added",
|
gst_element_link (comp, sink);
|
||||||
G_CALLBACK (composition_pad_added_cb), collect);
|
|
||||||
|
|
||||||
sinkpad = gst_element_get_static_pad (sink, "sink");
|
sinkpad = gst_element_get_static_pad (sink, "sink");
|
||||||
gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
|
gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
|
||||||
|
@ -521,7 +521,8 @@ GST_START_TEST (test_complex_operations)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
oper =
|
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);
|
fail_if (oper == NULL);
|
||||||
check_start_stop_duration (oper, 2 * GST_SECOND, 4 * GST_SECOND,
|
check_start_stop_duration (oper, 2 * GST_SECOND, 4 * GST_SECOND,
|
||||||
2 * GST_SECOND);
|
2 * GST_SECOND);
|
||||||
|
@ -639,7 +640,8 @@ GST_START_TEST (test_complex_operations_bis)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
oper =
|
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);
|
fail_if (oper == NULL);
|
||||||
check_start_stop_duration (oper, 2 * GST_SECOND, 4 * GST_SECOND,
|
check_start_stop_duration (oper, 2 * GST_SECOND, 4 * GST_SECOND,
|
||||||
2 * GST_SECOND);
|
2 * GST_SECOND);
|
||||||
|
@ -751,12 +753,26 @@ gnonlin_suite (void)
|
||||||
|
|
||||||
suite_add_tcase (s, tc_chain);
|
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_simplest);
|
||||||
tcase_add_test (tc_chain, test_one_after_other);
|
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_under_another);
|
||||||
tcase_add_test (tc_chain, test_one_bin_after_other);
|
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;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,9 +52,7 @@ test_simplest_full (void)
|
||||||
collect->expected_segments = g_list_append (collect->expected_segments,
|
collect->expected_segments = g_list_append (collect->expected_segments,
|
||||||
segment_new (1.0, GST_FORMAT_TIME, 5 * GST_SECOND, 6 * GST_SECOND, 0));
|
segment_new (1.0, GST_FORMAT_TIME, 5 * GST_SECOND, 6 * GST_SECOND, 0));
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (comp), "pad-added",
|
gst_element_link (comp, sink);
|
||||||
G_CALLBACK (composition_pad_added_cb), collect);
|
|
||||||
|
|
||||||
sinkpad = gst_element_get_static_pad (sink, "sink");
|
sinkpad = gst_element_get_static_pad (sink, "sink");
|
||||||
gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
|
gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
|
||||||
(GstPadProbeCallback) sinkpad_probe, collect, NULL);
|
(GstPadProbeCallback) sinkpad_probe, collect, NULL);
|
||||||
|
@ -282,8 +280,7 @@ test_one_after_other_full (void)
|
||||||
segment_new (1.0, GST_FORMAT_TIME,
|
segment_new (1.0, GST_FORMAT_TIME,
|
||||||
2 * GST_SECOND, 3 * GST_SECOND, 1 * GST_SECOND));
|
2 * GST_SECOND, 3 * GST_SECOND, 1 * GST_SECOND));
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (comp), "pad-added",
|
gst_element_link (comp, sink);
|
||||||
G_CALLBACK (composition_pad_added_cb), collect);
|
|
||||||
|
|
||||||
sinkpad = gst_element_get_static_pad (sink, "sink");
|
sinkpad = gst_element_get_static_pad (sink, "sink");
|
||||||
gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
|
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,
|
segment_new (1.0, GST_FORMAT_TIME,
|
||||||
2 * GST_SECOND, 3 * GST_SECOND, 2 * GST_SECOND));
|
2 * GST_SECOND, 3 * GST_SECOND, 2 * GST_SECOND));
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (comp), "pad-added",
|
gst_element_link (comp, sink);
|
||||||
G_CALLBACK (composition_pad_added_cb), collect);
|
|
||||||
|
|
||||||
sinkpad = gst_element_get_static_pad (sink, "sink");
|
sinkpad = gst_element_get_static_pad (sink, "sink");
|
||||||
gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
|
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,
|
segment_new (1.0, GST_FORMAT_TIME,
|
||||||
1 * GST_SECOND, 2 * GST_SECOND, 1 * GST_SECOND));
|
1 * GST_SECOND, 2 * GST_SECOND, 1 * GST_SECOND));
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (comp), "pad-added",
|
gst_element_link (comp, sink);
|
||||||
G_CALLBACK (composition_pad_added_cb), collect);
|
|
||||||
|
|
||||||
sinkpad = gst_element_get_static_pad (sink, "sink");
|
sinkpad = gst_element_get_static_pad (sink, "sink");
|
||||||
gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
|
gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
|
||||||
|
|
Loading…
Reference in a new issue