2000-12-28 22:12:02 +00:00
|
|
|
/* GStreamer
|
2002-06-11 21:03:48 +00:00
|
|
|
*
|
2000-12-28 22:12:02 +00:00
|
|
|
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
|
|
|
* 2000 Wim Taymans <wtay@chello.be>
|
|
|
|
*
|
|
|
|
* gstbin.c: GstBin container object and support code
|
2000-01-30 09:03:00 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this library; if not, write to the
|
|
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
2000-12-28 22:12:02 +00:00
|
|
|
#include "gst_private.h"
|
2000-12-08 18:24:16 +00:00
|
|
|
|
2001-12-18 19:03:07 +00:00
|
|
|
#include "gstevent.h"
|
2000-12-15 01:57:34 +00:00
|
|
|
#include "gstbin.h"
|
2004-02-03 03:31:26 +00:00
|
|
|
#include "gstmarshal.h"
|
2002-02-03 20:07:09 +00:00
|
|
|
#include "gstxml.h"
|
2003-06-29 14:05:49 +00:00
|
|
|
#include "gstinfo.h"
|
2004-02-24 12:41:19 +00:00
|
|
|
#include "gsterror.h"
|
2000-08-21 21:20:38 +00:00
|
|
|
|
2000-12-26 23:51:04 +00:00
|
|
|
#include "gstscheduler.h"
|
2002-12-19 21:31:03 +00:00
|
|
|
#include "gstindex.h"
|
2004-07-12 21:27:11 +00:00
|
|
|
#include "gstutils.h"
|
2000-12-26 23:51:04 +00:00
|
|
|
|
2004-08-03 09:51:37 +00:00
|
|
|
GST_DEBUG_CATEGORY_STATIC (bin_debug);
|
|
|
|
#define GST_CAT_DEFAULT bin_debug
|
|
|
|
#define GST_LOG_BIN_CONTENTS(bin, text) GST_LOG_OBJECT ((bin), \
|
|
|
|
text ": %d elements: %u PLAYING, %u PAUSED, %u READY, %u NULL, own state: %s", \
|
|
|
|
(bin)->numchildren, (guint) (bin)->child_states[3], \
|
|
|
|
(guint) (bin)->child_states[2], (bin)->child_states[1], \
|
|
|
|
(bin)->child_states[0], gst_element_state_get_name (GST_STATE (bin)))
|
|
|
|
|
|
|
|
|
2004-03-13 15:27:01 +00:00
|
|
|
static GstElementDetails gst_bin_details = GST_ELEMENT_DETAILS ("Generic bin",
|
|
|
|
"Generic/Bin",
|
|
|
|
"Simple container object",
|
|
|
|
"Erik Walthinsen <omega@cse.ogi.edu>");
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2004-06-12 13:45:17 +00:00
|
|
|
GType _gst_bin_type = 0;
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2004-03-13 15:27:01 +00:00
|
|
|
static gboolean _gst_boolean_did_something_accumulator (GSignalInvocationHint *
|
|
|
|
ihint, GValue * return_accu, const GValue * handler_return, gpointer dummy);
|
2003-10-14 00:00:37 +00:00
|
|
|
|
2004-03-13 15:27:01 +00:00
|
|
|
static void gst_bin_dispose (GObject * object);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2004-07-29 20:33:49 +00:00
|
|
|
static GstElementStateReturn gst_bin_change_state (GstElement * element);
|
2004-03-13 15:27:01 +00:00
|
|
|
static GstElementStateReturn gst_bin_change_state_norecurse (GstBin * bin);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2003-02-10 20:32:32 +00:00
|
|
|
#ifndef GST_DISABLE_INDEX
|
2004-03-13 15:27:01 +00:00
|
|
|
static void gst_bin_set_index (GstElement * element, GstIndex * index);
|
2003-02-10 20:32:32 +00:00
|
|
|
#endif
|
2002-12-19 21:31:03 +00:00
|
|
|
|
2004-03-13 15:27:01 +00:00
|
|
|
static void gst_bin_add_func (GstBin * bin, GstElement * element);
|
|
|
|
static void gst_bin_remove_func (GstBin * bin, GstElement * element);
|
|
|
|
static void gst_bin_child_state_change_func (GstBin * bin,
|
|
|
|
GstElementState oldstate, GstElementState newstate, GstElement * child);
|
2004-07-12 21:27:11 +00:00
|
|
|
GstElementStateReturn gst_bin_set_state (GstElement * element,
|
|
|
|
GstElementState state);
|
2003-01-11 20:08:03 +00:00
|
|
|
|
2004-03-13 15:27:01 +00:00
|
|
|
static GstClock *gst_bin_get_clock_func (GstElement * element);
|
|
|
|
static void gst_bin_set_clock_func (GstElement * element, GstClock * clock);
|
2003-02-10 20:32:32 +00:00
|
|
|
|
2004-03-13 15:27:01 +00:00
|
|
|
static gboolean gst_bin_iterate_func (GstBin * bin);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2001-06-25 06:45:56 +00:00
|
|
|
#ifndef GST_DISABLE_LOADSAVE
|
2004-03-13 15:27:01 +00:00
|
|
|
static xmlNodePtr gst_bin_save_thyself (GstObject * object, xmlNodePtr parent);
|
|
|
|
static void gst_bin_restore_thyself (GstObject * object, xmlNodePtr self);
|
2001-06-24 21:18:28 +00:00
|
|
|
#endif
|
2000-01-30 09:03:00 +00:00
|
|
|
|
|
|
|
/* Bin signals and args */
|
2001-12-15 22:37:35 +00:00
|
|
|
enum
|
|
|
|
{
|
2002-12-19 21:31:03 +00:00
|
|
|
ELEMENT_ADDED,
|
|
|
|
ELEMENT_REMOVED,
|
2003-10-14 00:00:37 +00:00
|
|
|
ITERATE,
|
2000-01-30 09:03:00 +00:00
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
2001-12-15 22:37:35 +00:00
|
|
|
enum
|
|
|
|
{
|
2003-05-15 22:46:37 +00:00
|
|
|
ARG_0
|
2004-03-13 15:27:01 +00:00
|
|
|
/* FILL ME */
|
2000-01-30 09:03:00 +00:00
|
|
|
};
|
|
|
|
|
2004-03-13 15:27:01 +00:00
|
|
|
static void gst_bin_base_init (gpointer g_class);
|
|
|
|
static void gst_bin_class_init (GstBinClass * klass);
|
|
|
|
static void gst_bin_init (GstBin * bin);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
|
|
|
static GstElementClass *parent_class = NULL;
|
|
|
|
static guint gst_bin_signals[LAST_SIGNAL] = { 0 };
|
|
|
|
|
2004-03-26 03:46:16 +00:00
|
|
|
/**
|
|
|
|
* gst_bin_get_type:
|
|
|
|
*
|
|
|
|
* Returns: the type of #GstBin
|
|
|
|
*/
|
2001-06-25 01:20:11 +00:00
|
|
|
GType
|
2001-01-20 03:10:44 +00:00
|
|
|
gst_bin_get_type (void)
|
2000-11-04 18:54:07 +00:00
|
|
|
{
|
2001-10-21 18:00:31 +00:00
|
|
|
if (!_gst_bin_type) {
|
2001-06-25 01:20:11 +00:00
|
|
|
static const GTypeInfo bin_info = {
|
2001-12-15 22:37:35 +00:00
|
|
|
sizeof (GstBinClass),
|
2003-10-31 19:32:47 +00:00
|
|
|
gst_bin_base_init,
|
2001-06-25 01:20:11 +00:00
|
|
|
NULL,
|
2001-12-15 22:37:35 +00:00
|
|
|
(GClassInitFunc) gst_bin_class_init,
|
2001-06-25 01:20:11 +00:00
|
|
|
NULL,
|
|
|
|
NULL,
|
2001-12-15 22:37:35 +00:00
|
|
|
sizeof (GstBin),
|
2004-04-09 19:05:03 +00:00
|
|
|
0,
|
2001-12-15 22:37:35 +00:00
|
|
|
(GInstanceInitFunc) gst_bin_init,
|
2001-09-14 22:16:47 +00:00
|
|
|
NULL
|
2000-01-30 09:03:00 +00:00
|
|
|
};
|
2001-12-15 22:37:35 +00:00
|
|
|
|
2004-03-13 15:27:01 +00:00
|
|
|
_gst_bin_type =
|
2004-03-15 19:27:17 +00:00
|
|
|
g_type_register_static (GST_TYPE_ELEMENT, "GstBin", &bin_info, 0);
|
2004-08-03 09:51:37 +00:00
|
|
|
|
|
|
|
GST_DEBUG_CATEGORY_INIT (bin_debug, "bin", GST_DEBUG_BOLD,
|
|
|
|
"debugging info for the 'bin' container element");
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
2001-10-21 18:00:31 +00:00
|
|
|
return _gst_bin_type;
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
|
|
|
|
2003-10-31 19:32:47 +00:00
|
|
|
static void
|
|
|
|
gst_bin_base_init (gpointer g_class)
|
|
|
|
{
|
|
|
|
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
|
2004-03-13 15:27:01 +00:00
|
|
|
|
2003-10-31 19:32:47 +00:00
|
|
|
gst_element_class_set_details (gstelement_class, &gst_bin_details);
|
|
|
|
}
|
|
|
|
|
2000-01-30 09:03:00 +00:00
|
|
|
static void
|
2001-12-15 22:37:35 +00:00
|
|
|
gst_bin_class_init (GstBinClass * klass)
|
2000-11-04 18:54:07 +00:00
|
|
|
{
|
2001-06-25 01:20:11 +00:00
|
|
|
GObjectClass *gobject_class;
|
2001-01-29 00:06:02 +00:00
|
|
|
GstObjectClass *gstobject_class;
|
2000-01-30 09:03:00 +00:00
|
|
|
GstElementClass *gstelement_class;
|
|
|
|
|
2001-12-15 22:37:35 +00:00
|
|
|
gobject_class = (GObjectClass *) klass;
|
|
|
|
gstobject_class = (GstObjectClass *) klass;
|
|
|
|
gstelement_class = (GstElementClass *) klass;
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2001-06-25 01:20:11 +00:00
|
|
|
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2002-12-19 21:31:03 +00:00
|
|
|
gst_bin_signals[ELEMENT_ADDED] =
|
2004-03-13 15:27:01 +00:00
|
|
|
g_signal_new ("element-added", G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_added), NULL,
|
|
|
|
NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
|
2002-12-19 21:31:03 +00:00
|
|
|
gst_bin_signals[ELEMENT_REMOVED] =
|
2004-03-13 15:27:01 +00:00
|
|
|
g_signal_new ("element-removed", G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_removed), NULL,
|
|
|
|
NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
|
2003-10-14 00:00:37 +00:00
|
|
|
gst_bin_signals[ITERATE] =
|
2004-03-13 15:27:01 +00:00
|
|
|
g_signal_new ("iterate", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET (GstBinClass, iterate),
|
|
|
|
_gst_boolean_did_something_accumulator, NULL, gst_marshal_BOOLEAN__VOID,
|
|
|
|
G_TYPE_BOOLEAN, 0);
|
2001-12-18 19:03:07 +00:00
|
|
|
|
2004-03-13 15:27:01 +00:00
|
|
|
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_bin_dispose);
|
2002-01-18 22:44:19 +00:00
|
|
|
|
2001-06-25 06:45:56 +00:00
|
|
|
#ifndef GST_DISABLE_LOADSAVE
|
2004-03-13 15:27:01 +00:00
|
|
|
gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_bin_save_thyself);
|
|
|
|
gstobject_class->restore_thyself =
|
|
|
|
GST_DEBUG_FUNCPTR (gst_bin_restore_thyself);
|
2001-06-24 21:18:28 +00:00
|
|
|
#endif
|
2001-01-29 00:06:02 +00:00
|
|
|
|
2004-07-29 20:33:49 +00:00
|
|
|
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_bin_change_state);
|
2004-07-12 21:27:11 +00:00
|
|
|
gstelement_class->set_state = GST_DEBUG_FUNCPTR (gst_bin_set_state);
|
2003-02-10 20:32:32 +00:00
|
|
|
#ifndef GST_DISABLE_INDEX
|
2004-03-13 15:27:01 +00:00
|
|
|
gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_bin_set_index);
|
2003-02-10 20:32:32 +00:00
|
|
|
#endif
|
2001-10-17 10:21:27 +00:00
|
|
|
|
2004-03-13 15:27:01 +00:00
|
|
|
klass->add_element = GST_DEBUG_FUNCPTR (gst_bin_add_func);
|
|
|
|
klass->remove_element = GST_DEBUG_FUNCPTR (gst_bin_remove_func);
|
|
|
|
klass->child_state_change =
|
|
|
|
GST_DEBUG_FUNCPTR (gst_bin_child_state_change_func);
|
|
|
|
klass->iterate = GST_DEBUG_FUNCPTR (gst_bin_iterate_func);
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
|
|
|
|
2003-10-14 00:00:37 +00:00
|
|
|
static gboolean
|
2004-03-13 15:27:01 +00:00
|
|
|
_gst_boolean_did_something_accumulator (GSignalInvocationHint * ihint,
|
|
|
|
GValue * return_accu, const GValue * handler_return, gpointer dummy)
|
2003-10-14 00:00:37 +00:00
|
|
|
{
|
|
|
|
gboolean did_something;
|
|
|
|
|
|
|
|
did_something = g_value_get_boolean (handler_return);
|
|
|
|
if (did_something) {
|
|
|
|
g_value_set_boolean (return_accu, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* always continue emission */
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2001-01-20 03:10:44 +00:00
|
|
|
static void
|
2001-12-15 22:37:35 +00:00
|
|
|
gst_bin_init (GstBin * bin)
|
2000-11-04 18:54:07 +00:00
|
|
|
{
|
2001-12-14 22:59:21 +00:00
|
|
|
/* in general, we prefer to use cothreads for most things */
|
2000-12-20 09:39:43 +00:00
|
|
|
GST_FLAG_SET (bin, GST_BIN_FLAG_PREFER_COTHREADS);
|
|
|
|
|
2000-01-30 09:03:00 +00:00
|
|
|
bin->numchildren = 0;
|
|
|
|
bin->children = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_bin_new:
|
|
|
|
* @name: name of new bin
|
|
|
|
*
|
|
|
|
* Create a new bin with given name.
|
|
|
|
*
|
|
|
|
* Returns: new bin
|
|
|
|
*/
|
2001-12-15 22:37:35 +00:00
|
|
|
GstElement *
|
|
|
|
gst_bin_new (const gchar * name)
|
2000-11-04 18:54:07 +00:00
|
|
|
{
|
2002-04-11 20:35:18 +00:00
|
|
|
return gst_element_factory_make ("bin", name);
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
|
|
|
|
2004-03-13 15:27:01 +00:00
|
|
|
static GstClock *
|
|
|
|
gst_bin_get_clock_func (GstElement * element)
|
2003-02-10 20:32:32 +00:00
|
|
|
{
|
2004-03-13 15:27:01 +00:00
|
|
|
if (GST_ELEMENT_SCHED (element))
|
2003-02-11 20:15:50 +00:00
|
|
|
return gst_scheduler_get_clock (GST_ELEMENT_SCHED (element));
|
2003-02-10 20:32:32 +00:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_bin_set_clock_func (GstElement * element, GstClock * clock)
|
2003-02-10 20:32:32 +00:00
|
|
|
{
|
2004-03-13 15:27:01 +00:00
|
|
|
if (GST_ELEMENT_SCHED (element))
|
2003-02-11 20:15:50 +00:00
|
|
|
gst_scheduler_use_clock (GST_ELEMENT_SCHED (element), clock);
|
2003-02-10 20:32:32 +00:00
|
|
|
}
|
|
|
|
|
2002-03-31 14:04:50 +00:00
|
|
|
/**
|
|
|
|
* gst_bin_get_clock:
|
2002-04-23 15:02:35 +00:00
|
|
|
* @bin: a #GstBin to get the clock of
|
2002-03-31 14:04:50 +00:00
|
|
|
*
|
2002-04-23 15:02:35 +00:00
|
|
|
* Gets the current clock of the (scheduler of the) bin.
|
2002-03-31 14:04:50 +00:00
|
|
|
*
|
2002-04-23 15:02:35 +00:00
|
|
|
* Returns: the #GstClock of the bin
|
2002-03-31 14:04:50 +00:00
|
|
|
*/
|
2004-03-13 15:27:01 +00:00
|
|
|
GstClock *
|
|
|
|
gst_bin_get_clock (GstBin * bin)
|
2002-02-03 20:07:09 +00:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (bin != NULL, NULL);
|
|
|
|
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
|
|
|
|
|
2003-02-11 20:15:50 +00:00
|
|
|
return gst_bin_get_clock_func (GST_ELEMENT (bin));
|
2002-02-03 20:07:09 +00:00
|
|
|
}
|
|
|
|
|
2002-03-31 14:04:50 +00:00
|
|
|
/**
|
|
|
|
* gst_bin_use_clock:
|
|
|
|
* @bin: the bin to set the clock for
|
|
|
|
* @clock: the clock to use.
|
|
|
|
*
|
|
|
|
* Force the bin to use the given clock. Use NULL to
|
|
|
|
* force it to use no clock at all.
|
|
|
|
*/
|
2002-02-03 20:07:09 +00:00
|
|
|
void
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_bin_use_clock (GstBin * bin, GstClock * clock)
|
2002-02-03 20:07:09 +00:00
|
|
|
{
|
|
|
|
g_return_if_fail (GST_IS_BIN (bin));
|
|
|
|
|
2003-02-12 17:23:45 +00:00
|
|
|
gst_bin_set_clock_func (GST_ELEMENT (bin), clock);
|
2002-02-03 20:07:09 +00:00
|
|
|
}
|
|
|
|
|
2002-03-31 14:04:50 +00:00
|
|
|
/**
|
|
|
|
* gst_bin_auto_clock:
|
|
|
|
* @bin: the bin to autoclock
|
|
|
|
*
|
|
|
|
* Let the bin select a clock automatically.
|
|
|
|
*/
|
2002-02-03 20:07:09 +00:00
|
|
|
void
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_bin_auto_clock (GstBin * bin)
|
2002-02-03 20:07:09 +00:00
|
|
|
{
|
|
|
|
g_return_if_fail (GST_IS_BIN (bin));
|
|
|
|
|
2004-03-13 15:27:01 +00:00
|
|
|
if (GST_ELEMENT_SCHED (bin))
|
2002-03-30 17:05:03 +00:00
|
|
|
gst_scheduler_auto_clock (GST_ELEMENT_SCHED (bin));
|
2002-02-03 20:07:09 +00:00
|
|
|
}
|
|
|
|
|
2003-02-10 20:32:32 +00:00
|
|
|
#ifndef GST_DISABLE_INDEX
|
2001-09-14 22:16:47 +00:00
|
|
|
static void
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_bin_set_index (GstElement * element, GstIndex * index)
|
2001-05-25 21:00:07 +00:00
|
|
|
{
|
2003-02-10 07:53:58 +00:00
|
|
|
GstBin *bin = GST_BIN (element);
|
2004-03-13 15:27:01 +00:00
|
|
|
|
2002-12-19 21:31:03 +00:00
|
|
|
g_return_if_fail (GST_IS_BIN (bin));
|
|
|
|
|
2003-04-14 18:38:11 +00:00
|
|
|
g_list_foreach (bin->children, (GFunc) gst_element_set_index, index);
|
2002-12-19 21:31:03 +00:00
|
|
|
}
|
2003-02-10 20:32:32 +00:00
|
|
|
#endif
|
2002-12-19 21:31:03 +00:00
|
|
|
|
|
|
|
static void
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_bin_set_element_sched (GstElement * element, GstScheduler * sched)
|
2002-12-19 21:31:03 +00:00
|
|
|
{
|
2004-02-20 13:18:32 +00:00
|
|
|
GST_CAT_LOG (GST_CAT_SCHEDULING, "setting element \"%s\" sched to %p",
|
2004-03-13 15:27:01 +00:00
|
|
|
GST_ELEMENT_NAME (element), sched);
|
2001-05-25 21:00:07 +00:00
|
|
|
|
2001-12-14 22:59:21 +00:00
|
|
|
/* if it's actually a Bin */
|
2001-12-15 22:37:35 +00:00
|
|
|
if (GST_IS_BIN (element)) {
|
2001-12-04 22:12:50 +00:00
|
|
|
if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
|
2004-02-20 13:18:32 +00:00
|
|
|
GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element,
|
2004-03-15 19:27:17 +00:00
|
|
|
"child is already a manager, not resetting sched");
|
2002-07-28 01:46:38 +00:00
|
|
|
if (GST_ELEMENT_SCHED (element))
|
2004-03-15 19:27:17 +00:00
|
|
|
gst_scheduler_add_scheduler (sched, GST_ELEMENT_SCHED (element));
|
2001-05-25 21:00:07 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-02-20 13:18:32 +00:00
|
|
|
GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element,
|
2004-03-15 19:27:17 +00:00
|
|
|
"setting child bin's scheduler to be the same as the parent's");
|
2001-12-04 22:12:50 +00:00
|
|
|
gst_scheduler_add_element (sched, element);
|
2001-05-25 21:00:07 +00:00
|
|
|
|
2001-12-14 22:59:21 +00:00
|
|
|
/* set the children's schedule */
|
2004-03-13 15:27:01 +00:00
|
|
|
g_list_foreach (GST_BIN (element)->children,
|
2004-03-15 19:27:17 +00:00
|
|
|
(GFunc) gst_bin_set_element_sched, sched);
|
2001-12-15 22:37:35 +00:00
|
|
|
}
|
2001-12-14 22:59:21 +00:00
|
|
|
/* otherwise, if it's just a regular old element */
|
2004-03-28 02:29:24 +00:00
|
|
|
else if (!GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
|
2002-11-02 13:54:34 +00:00
|
|
|
GList *pads;
|
2003-01-09 14:15:37 +00:00
|
|
|
|
2001-12-04 22:12:50 +00:00
|
|
|
gst_scheduler_add_element (sched, element);
|
2003-01-09 14:15:37 +00:00
|
|
|
|
2002-11-02 13:54:34 +00:00
|
|
|
/* set the sched pointer in all the pads */
|
|
|
|
pads = element->pads;
|
|
|
|
while (pads) {
|
|
|
|
GstPad *pad;
|
|
|
|
|
|
|
|
pad = GST_PAD (pads->data);
|
|
|
|
pads = g_list_next (pads);
|
2003-01-09 14:15:37 +00:00
|
|
|
|
2002-11-02 13:54:34 +00:00
|
|
|
/* we only operate on real pads */
|
|
|
|
if (!GST_IS_REAL_PAD (pad))
|
2004-03-15 19:27:17 +00:00
|
|
|
continue;
|
2002-11-02 13:54:34 +00:00
|
|
|
|
|
|
|
/* if the peer element exists and is a candidate */
|
|
|
|
if (GST_PAD_PEER (pad)) {
|
2004-03-15 19:27:17 +00:00
|
|
|
if (gst_pad_get_scheduler (GST_PAD_PEER (pad)) == sched) {
|
|
|
|
GST_CAT_LOG (GST_CAT_SCHEDULING,
|
|
|
|
"peer is in same scheduler, telling scheduler");
|
|
|
|
|
|
|
|
if (GST_PAD_IS_SRC (pad))
|
|
|
|
gst_scheduler_pad_link (sched, pad, GST_PAD_PEER (pad));
|
|
|
|
else
|
|
|
|
gst_scheduler_pad_link (sched, GST_PAD_PEER (pad), pad);
|
|
|
|
}
|
2002-11-02 13:54:34 +00:00
|
|
|
}
|
|
|
|
}
|
2001-05-25 21:00:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-09-14 22:16:47 +00:00
|
|
|
static void
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_bin_unset_element_sched (GstElement * element, GstScheduler * sched)
|
2001-05-25 21:00:07 +00:00
|
|
|
{
|
2001-12-19 19:22:53 +00:00
|
|
|
if (GST_ELEMENT_SCHED (element) == NULL) {
|
2004-02-20 13:18:32 +00:00
|
|
|
GST_CAT_DEBUG (GST_CAT_SCHEDULING, "element \"%s\" has no scheduler",
|
2004-03-15 19:27:17 +00:00
|
|
|
GST_ELEMENT_NAME (element));
|
2001-12-19 19:22:53 +00:00
|
|
|
return;
|
|
|
|
}
|
2003-01-09 14:15:37 +00:00
|
|
|
|
2004-03-13 15:27:01 +00:00
|
|
|
GST_CAT_DEBUG (GST_CAT_SCHEDULING,
|
|
|
|
"removing element \"%s\" from its sched %p", GST_ELEMENT_NAME (element),
|
|
|
|
GST_ELEMENT_SCHED (element));
|
2001-05-25 21:00:07 +00:00
|
|
|
|
2001-12-14 22:59:21 +00:00
|
|
|
/* if it's actually a Bin */
|
2001-12-15 22:37:35 +00:00
|
|
|
if (GST_IS_BIN (element)) {
|
2001-05-25 21:00:07 +00:00
|
|
|
|
2001-12-15 22:37:35 +00:00
|
|
|
if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
|
2004-02-20 13:18:32 +00:00
|
|
|
GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element,
|
2004-03-15 19:27:17 +00:00
|
|
|
"child is already a manager, not unsetting sched");
|
2002-03-30 17:05:03 +00:00
|
|
|
if (sched) {
|
2004-03-15 19:27:17 +00:00
|
|
|
gst_scheduler_remove_scheduler (sched, GST_ELEMENT_SCHED (element));
|
2002-03-30 17:05:03 +00:00
|
|
|
}
|
2001-05-25 21:00:07 +00:00
|
|
|
return;
|
|
|
|
}
|
2001-12-14 22:59:21 +00:00
|
|
|
/* for each child, remove them from their schedule */
|
2004-03-13 15:27:01 +00:00
|
|
|
g_list_foreach (GST_BIN (element)->children,
|
2004-03-15 19:27:17 +00:00
|
|
|
(GFunc) gst_bin_unset_element_sched, sched);
|
2001-05-25 21:00:07 +00:00
|
|
|
|
2002-03-30 17:05:03 +00:00
|
|
|
gst_scheduler_remove_element (GST_ELEMENT_SCHED (element), element);
|
2004-03-28 02:29:24 +00:00
|
|
|
} else if (!GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
|
|
|
|
/* otherwise, if it's just a regular old element */
|
2002-11-02 13:54:34 +00:00
|
|
|
GList *pads;
|
|
|
|
|
|
|
|
/* set the sched pointer in all the pads */
|
|
|
|
pads = element->pads;
|
|
|
|
while (pads) {
|
|
|
|
GstPad *pad;
|
|
|
|
|
|
|
|
pad = GST_PAD (pads->data);
|
|
|
|
pads = g_list_next (pads);
|
|
|
|
|
|
|
|
/* we only operate on real pads */
|
|
|
|
if (!GST_IS_REAL_PAD (pad))
|
2004-03-15 19:27:17 +00:00
|
|
|
continue;
|
2002-11-02 13:54:34 +00:00
|
|
|
|
|
|
|
/* if the peer element exists and is a candidate */
|
|
|
|
if (GST_PAD_PEER (pad)) {
|
2004-03-15 19:27:17 +00:00
|
|
|
if (gst_pad_get_scheduler (GST_PAD_PEER (pad)) == sched) {
|
|
|
|
GST_CAT_LOG (GST_CAT_SCHEDULING,
|
|
|
|
"peer is in same scheduler, telling scheduler");
|
|
|
|
|
|
|
|
if (GST_PAD_IS_SRC (pad))
|
|
|
|
gst_scheduler_pad_unlink (sched, pad, GST_PAD_PEER (pad));
|
|
|
|
else
|
|
|
|
gst_scheduler_pad_unlink (sched, GST_PAD_PEER (pad), pad);
|
|
|
|
}
|
2002-11-02 13:54:34 +00:00
|
|
|
}
|
|
|
|
}
|
2001-12-15 22:37:35 +00:00
|
|
|
gst_scheduler_remove_element (GST_ELEMENT_SCHED (element), element);
|
2001-05-25 21:00:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-02-21 14:44:27 +00:00
|
|
|
/**
|
2002-03-31 14:04:50 +00:00
|
|
|
* gst_bin_add_many:
|
|
|
|
* @bin: the bin to add the elements to
|
2002-02-21 14:44:27 +00:00
|
|
|
* @element_1: the first element to add to the bin
|
2004-03-26 03:46:16 +00:00
|
|
|
* @...: additional elements to add to the bin
|
2002-02-21 14:44:27 +00:00
|
|
|
*
|
2004-03-26 03:46:16 +00:00
|
|
|
* Adds a NULL-terminated list of elements to a bin. This function is
|
|
|
|
* equivalent to calling #gst_bin_add() for each member of the list.
|
2002-03-31 14:04:50 +00:00
|
|
|
*/
|
2002-02-21 14:44:27 +00:00
|
|
|
void
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_bin_add_many (GstBin * bin, GstElement * element_1, ...)
|
2002-02-21 14:44:27 +00:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
g_return_if_fail (GST_IS_BIN (bin));
|
|
|
|
g_return_if_fail (GST_IS_ELEMENT (element_1));
|
|
|
|
|
|
|
|
va_start (args, element_1);
|
|
|
|
|
|
|
|
while (element_1) {
|
|
|
|
gst_bin_add (bin, element_1);
|
2004-03-13 15:27:01 +00:00
|
|
|
|
|
|
|
element_1 = va_arg (args, GstElement *);
|
2002-02-21 14:44:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
va_end (args);
|
|
|
|
}
|
|
|
|
|
2003-01-11 20:08:03 +00:00
|
|
|
static void
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_bin_add_func (GstBin * bin, GstElement * element)
|
2000-11-04 18:54:07 +00:00
|
|
|
{
|
2001-12-10 18:08:35 +00:00
|
|
|
gint state_idx = 0;
|
|
|
|
GstElementState state;
|
2002-03-30 17:05:03 +00:00
|
|
|
GstScheduler *sched;
|
2001-12-10 18:08:35 +00:00
|
|
|
|
2003-03-25 19:39:18 +00:00
|
|
|
/* the element must not already have a parent */
|
|
|
|
g_return_if_fail (GST_ELEMENT_PARENT (element) == NULL);
|
|
|
|
|
2001-12-14 22:59:21 +00:00
|
|
|
/* then check to see if the element's name is already taken in the bin */
|
2004-03-13 15:27:01 +00:00
|
|
|
if (gst_object_check_uniqueness (bin->children,
|
2004-03-15 19:27:17 +00:00
|
|
|
GST_ELEMENT_NAME (element)) == FALSE) {
|
2002-04-21 14:16:36 +00:00
|
|
|
g_warning ("Name %s is not unique in bin %s, not adding\n",
|
2004-03-15 19:27:17 +00:00
|
|
|
GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (bin));
|
2002-04-21 14:16:36 +00:00
|
|
|
return;
|
|
|
|
}
|
2000-07-17 17:14:15 +00:00
|
|
|
|
2004-07-29 20:33:49 +00:00
|
|
|
if (GST_STATE (element) > GST_STATE (bin)) {
|
|
|
|
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
|
|
|
|
"setting state to receive element \"%s\"", GST_OBJECT_NAME (element));
|
|
|
|
gst_element_set_state ((GstElement *) bin, GST_STATE (element));
|
|
|
|
}
|
2004-07-11 12:16:29 +00:00
|
|
|
|
2001-12-14 22:59:21 +00:00
|
|
|
/* set the element's parent and add the element to the bin's list of children */
|
2001-05-25 21:00:07 +00:00
|
|
|
gst_object_set_parent (GST_OBJECT (element), GST_OBJECT (bin));
|
2001-12-04 22:12:50 +00:00
|
|
|
|
2000-11-04 18:54:07 +00:00
|
|
|
bin->children = g_list_append (bin->children, element);
|
2000-01-30 09:03:00 +00:00
|
|
|
bin->numchildren++;
|
|
|
|
|
2001-12-14 22:59:21 +00:00
|
|
|
/* bump our internal state counter */
|
2001-12-10 18:08:35 +00:00
|
|
|
state = GST_STATE (element);
|
2004-03-13 15:27:01 +00:00
|
|
|
while (state >>= 1)
|
|
|
|
state_idx++;
|
2001-12-10 18:08:35 +00:00
|
|
|
bin->child_states[state_idx]++;
|
|
|
|
|
2001-12-15 22:37:35 +00:00
|
|
|
/* now we have to deal with manager stuff
|
|
|
|
* we can only do this if there's a scheduler:
|
|
|
|
* if we're not a manager, and aren't attached to anything, we have no sched (yet) */
|
2002-03-30 17:05:03 +00:00
|
|
|
sched = GST_ELEMENT_SCHED (bin);
|
|
|
|
if (sched) {
|
|
|
|
gst_bin_set_element_sched (element, sched);
|
2001-12-04 22:12:50 +00:00
|
|
|
}
|
2000-12-30 02:41:15 +00:00
|
|
|
|
2004-03-13 15:27:01 +00:00
|
|
|
GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, bin, "added element \"%s\"",
|
|
|
|
GST_OBJECT_NAME (element));
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2002-12-19 21:31:03 +00:00
|
|
|
g_signal_emit (G_OBJECT (bin), gst_bin_signals[ELEMENT_ADDED], 0, element);
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2003-01-11 20:08:03 +00:00
|
|
|
* gst_bin_add:
|
|
|
|
* @bin: #GstBin to add element to
|
|
|
|
* @element: #GstElement to add to bin
|
2000-01-30 09:03:00 +00:00
|
|
|
*
|
2004-03-26 03:46:16 +00:00
|
|
|
* Adds the given element to the bin. Sets the element's parent, and thus
|
|
|
|
* adds a reference.
|
2000-01-30 09:03:00 +00:00
|
|
|
*/
|
2001-01-20 03:10:44 +00:00
|
|
|
void
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_bin_add (GstBin * bin, GstElement * element)
|
2000-11-04 18:54:07 +00:00
|
|
|
{
|
2003-01-11 20:08:03 +00:00
|
|
|
GstBinClass *bclass;
|
2004-03-13 15:27:01 +00:00
|
|
|
|
2000-11-04 18:54:07 +00:00
|
|
|
g_return_if_fail (GST_IS_BIN (bin));
|
|
|
|
g_return_if_fail (GST_IS_ELEMENT (element));
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2004-02-20 13:18:32 +00:00
|
|
|
GST_CAT_INFO_OBJECT (GST_CAT_PARENTAGE, bin, "adding element \"%s\"",
|
2004-03-13 15:27:01 +00:00
|
|
|
GST_OBJECT_NAME (element));
|
2003-01-11 20:08:03 +00:00
|
|
|
|
|
|
|
bclass = GST_BIN_GET_CLASS (bin);
|
|
|
|
|
|
|
|
if (bclass->add_element) {
|
|
|
|
bclass->add_element (bin, element);
|
2004-03-13 15:27:01 +00:00
|
|
|
} else {
|
2004-02-24 12:41:19 +00:00
|
|
|
GST_ELEMENT_ERROR (bin, CORE, FAILED, (NULL),
|
2004-03-15 19:27:17 +00:00
|
|
|
("cannot add element %s to bin %s",
|
|
|
|
GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (bin)));
|
2003-01-11 20:08:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_bin_remove_func (GstBin * bin, GstElement * element)
|
2003-01-11 20:08:03 +00:00
|
|
|
{
|
|
|
|
gint state_idx = 0;
|
|
|
|
GstElementState state;
|
|
|
|
|
2001-12-14 22:59:21 +00:00
|
|
|
/* the element must have its parent set to the current bin */
|
2001-12-15 22:37:35 +00:00
|
|
|
g_return_if_fail (GST_ELEMENT_PARENT (element) == (GstObject *) bin);
|
2001-05-25 21:00:07 +00:00
|
|
|
|
2001-12-14 22:59:21 +00:00
|
|
|
/* the element must be in the bin's list of children */
|
2001-12-15 22:37:35 +00:00
|
|
|
if (g_list_find (bin->children, element) == NULL) {
|
|
|
|
g_warning ("no element \"%s\" in bin \"%s\"\n", GST_ELEMENT_NAME (element),
|
2004-03-15 19:27:17 +00:00
|
|
|
GST_ELEMENT_NAME (bin));
|
2000-12-30 02:41:15 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-12-14 22:59:21 +00:00
|
|
|
/* remove this element from the list of managed elements */
|
2002-03-30 17:05:03 +00:00
|
|
|
gst_bin_unset_element_sched (element, GST_ELEMENT_SCHED (bin));
|
2001-05-25 21:00:07 +00:00
|
|
|
|
2001-12-14 22:59:21 +00:00
|
|
|
/* now remove the element from the list of elements */
|
2000-11-04 18:54:07 +00:00
|
|
|
bin->children = g_list_remove (bin->children, element);
|
2000-01-30 09:03:00 +00:00
|
|
|
bin->numchildren--;
|
2000-07-17 17:14:15 +00:00
|
|
|
|
2001-12-14 22:59:21 +00:00
|
|
|
/* bump our internal state counter */
|
2001-12-10 18:08:35 +00:00
|
|
|
state = GST_STATE (element);
|
2004-03-13 15:27:01 +00:00
|
|
|
while (state >>= 1)
|
|
|
|
state_idx++;
|
2001-12-10 18:08:35 +00:00
|
|
|
bin->child_states[state_idx]--;
|
|
|
|
|
2004-07-29 20:33:49 +00:00
|
|
|
GST_CAT_INFO_OBJECT (GST_CAT_PARENTAGE, bin, "removed child \"%s\"",
|
|
|
|
GST_OBJECT_NAME (element));
|
2000-12-30 02:41:15 +00:00
|
|
|
|
2002-12-19 21:31:03 +00:00
|
|
|
/* ref as we're going to emit a signal */
|
|
|
|
gst_object_ref (GST_OBJECT (element));
|
2001-05-25 21:00:07 +00:00
|
|
|
gst_object_unparent (GST_OBJECT (element));
|
|
|
|
|
2004-07-29 20:33:49 +00:00
|
|
|
/* if we're down to zero children, force state to NULL */
|
|
|
|
while (bin->numchildren == 0 && GST_ELEMENT_SCHED (bin) != NULL &&
|
|
|
|
GST_STATE (bin) > GST_STATE_NULL) {
|
|
|
|
GstElementState next = GST_STATE (bin) >> 1;
|
|
|
|
|
|
|
|
GST_STATE_PENDING (bin) = next;
|
|
|
|
gst_bin_change_state_norecurse (bin);
|
|
|
|
if (!GST_STATE (bin) == next) {
|
|
|
|
g_warning ("bin %s failed state change to %d", GST_ELEMENT_NAME (bin),
|
|
|
|
next);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2002-12-19 21:31:03 +00:00
|
|
|
g_signal_emit (G_OBJECT (bin), gst_bin_signals[ELEMENT_REMOVED], 0, element);
|
|
|
|
|
|
|
|
/* element is really out of our control now */
|
|
|
|
gst_object_unref (GST_OBJECT (element));
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
|
|
|
|
2003-01-11 20:08:03 +00:00
|
|
|
/**
|
|
|
|
* gst_bin_remove:
|
|
|
|
* @bin: #GstBin to remove element from
|
|
|
|
* @element: #GstElement to remove
|
|
|
|
*
|
2004-03-26 03:46:16 +00:00
|
|
|
* Remove the element from its associated bin, unparenting it as well.
|
|
|
|
* Unparenting the element means that the element will be dereferenced,
|
|
|
|
* so if the bin holds the only reference to the element, the element
|
|
|
|
* will be freed in the process of removing it from the bin. If you
|
|
|
|
* want the element to still exist after removing, you need to call
|
2003-01-11 20:08:03 +00:00
|
|
|
* #gst_object_ref before removing it from the bin.
|
|
|
|
*/
|
|
|
|
void
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_bin_remove (GstBin * bin, GstElement * element)
|
2003-01-11 20:08:03 +00:00
|
|
|
{
|
|
|
|
GstBinClass *bclass;
|
|
|
|
|
2004-03-07 14:33:13 +00:00
|
|
|
GST_CAT_DEBUG (GST_CAT_PARENTAGE, "[%s]: trying to remove child %s",
|
2004-03-13 15:27:01 +00:00
|
|
|
GST_ELEMENT_NAME (bin), GST_ELEMENT_NAME (element));
|
2003-01-11 20:08:03 +00:00
|
|
|
|
|
|
|
g_return_if_fail (GST_IS_BIN (bin));
|
|
|
|
g_return_if_fail (GST_IS_ELEMENT (element));
|
|
|
|
|
|
|
|
bclass = GST_BIN_GET_CLASS (bin);
|
|
|
|
|
|
|
|
if (bclass->remove_element) {
|
|
|
|
bclass->remove_element (bin, element);
|
2004-03-13 15:27:01 +00:00
|
|
|
} else {
|
2003-01-11 20:08:03 +00:00
|
|
|
g_warning ("cannot remove elements from bin %s\n", GST_ELEMENT_NAME (bin));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-02-11 20:15:50 +00:00
|
|
|
/**
|
|
|
|
* gst_bin_remove_many:
|
|
|
|
* @bin: the bin to remove the elements from
|
|
|
|
* @element_1: the first element to remove from the bin
|
|
|
|
* @...: NULL-terminated list of elements to remove from the bin
|
|
|
|
*
|
2004-03-26 03:46:16 +00:00
|
|
|
* Remove a list of elements from a bin. This function is equivalent
|
|
|
|
* to calling #gst_bin_remove with each member of the list.
|
2003-02-11 20:15:50 +00:00
|
|
|
*/
|
|
|
|
void
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_bin_remove_many (GstBin * bin, GstElement * element_1, ...)
|
2003-02-11 20:15:50 +00:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
g_return_if_fail (GST_IS_BIN (bin));
|
|
|
|
g_return_if_fail (GST_IS_ELEMENT (element_1));
|
|
|
|
|
|
|
|
va_start (args, element_1);
|
|
|
|
|
|
|
|
while (element_1) {
|
|
|
|
gst_bin_remove (bin, element_1);
|
2004-03-13 15:27:01 +00:00
|
|
|
|
|
|
|
element_1 = va_arg (args, GstElement *);
|
2003-02-11 20:15:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
va_end (args);
|
|
|
|
}
|
|
|
|
|
2002-01-01 15:58:51 +00:00
|
|
|
/**
|
|
|
|
* gst_bin_child_state_change:
|
|
|
|
* @bin: #GstBin with the child
|
|
|
|
* @oldstate: The old child state
|
|
|
|
* @newstate: The new child state
|
|
|
|
* @child: #GstElement that signaled an changed state
|
|
|
|
*
|
|
|
|
* An internal function to inform the parent bin about a state change
|
|
|
|
* of a child.
|
|
|
|
*/
|
2001-12-20 20:03:10 +00:00
|
|
|
void
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_bin_child_state_change (GstBin * bin, GstElementState oldstate,
|
|
|
|
GstElementState newstate, GstElement * child)
|
2001-12-04 22:12:50 +00:00
|
|
|
{
|
2003-04-18 23:34:21 +00:00
|
|
|
GstBinClass *bclass;
|
2004-03-13 15:27:01 +00:00
|
|
|
|
2003-04-18 23:34:21 +00:00
|
|
|
g_return_if_fail (GST_IS_BIN (bin));
|
|
|
|
g_return_if_fail (GST_IS_ELEMENT (child));
|
2001-12-04 22:12:50 +00:00
|
|
|
|
2004-02-20 13:18:32 +00:00
|
|
|
GST_CAT_LOG (GST_CAT_STATES, "child %s changed state in bin %s from %s to %s",
|
2004-07-29 20:33:49 +00:00
|
|
|
GST_ELEMENT_NAME (child), GST_ELEMENT_NAME (bin),
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_element_state_get_name (oldstate),
|
|
|
|
gst_element_state_get_name (newstate));
|
2001-12-04 22:12:50 +00:00
|
|
|
|
2003-04-18 23:34:21 +00:00
|
|
|
bclass = GST_BIN_GET_CLASS (bin);
|
|
|
|
|
|
|
|
if (bclass->child_state_change) {
|
|
|
|
bclass->child_state_change (bin, oldstate, newstate, child);
|
2004-03-13 15:27:01 +00:00
|
|
|
} else {
|
|
|
|
g_warning ("cannot signal state change of child %s to bin %s\n",
|
2004-03-15 19:27:17 +00:00
|
|
|
GST_ELEMENT_NAME (child), GST_ELEMENT_NAME (bin));
|
2003-04-18 23:34:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_bin_child_state_change_func (GstBin * bin, GstElementState oldstate,
|
|
|
|
GstElementState newstate, GstElement * child)
|
2003-04-18 23:34:21 +00:00
|
|
|
{
|
2004-07-09 13:33:20 +00:00
|
|
|
GstElementState old = 0, new = 0;
|
2003-04-18 23:34:21 +00:00
|
|
|
gint old_idx = 0, new_idx = 0, i;
|
|
|
|
|
2004-07-09 13:33:20 +00:00
|
|
|
old = oldstate;
|
|
|
|
new = newstate;
|
|
|
|
while (old >>= 1)
|
2004-03-13 15:27:01 +00:00
|
|
|
old_idx++;
|
2004-07-09 13:33:20 +00:00
|
|
|
while (new >>= 1)
|
2004-03-13 15:27:01 +00:00
|
|
|
new_idx++;
|
2001-12-04 22:12:50 +00:00
|
|
|
|
2004-07-29 20:33:49 +00:00
|
|
|
GST_LOCK (bin);
|
2004-08-03 09:51:37 +00:00
|
|
|
GST_LOG_BIN_CONTENTS (bin, "before child state change");
|
2001-12-04 22:12:50 +00:00
|
|
|
bin->child_states[old_idx]--;
|
|
|
|
bin->child_states[new_idx]++;
|
2004-03-13 15:27:01 +00:00
|
|
|
|
2001-12-15 22:37:35 +00:00
|
|
|
for (i = GST_NUM_STATES - 1; i >= 0; i--) {
|
2001-12-04 22:12:50 +00:00
|
|
|
if (bin->child_states[i] != 0) {
|
2002-01-01 13:51:04 +00:00
|
|
|
gint state = (1 << i);
|
2004-03-13 15:27:01 +00:00
|
|
|
|
2002-01-01 13:51:04 +00:00
|
|
|
if (GST_STATE (bin) != state) {
|
2004-03-15 19:27:17 +00:00
|
|
|
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
|
|
|
|
"highest child state is %s, changing bin state accordingly",
|
|
|
|
gst_element_state_get_name (state));
|
|
|
|
GST_STATE_PENDING (bin) = state;
|
2004-07-29 20:33:49 +00:00
|
|
|
GST_UNLOCK (bin);
|
2004-03-15 19:27:17 +00:00
|
|
|
gst_bin_change_state_norecurse (bin);
|
|
|
|
if (state != GST_STATE (bin)) {
|
2004-07-29 20:33:49 +00:00
|
|
|
g_warning ("%s: state change in callback %d %d",
|
|
|
|
GST_ELEMENT_NAME (bin), state, GST_STATE (bin));
|
2004-03-15 19:27:17 +00:00
|
|
|
}
|
2004-08-03 09:51:37 +00:00
|
|
|
GST_LOG_BIN_CONTENTS (bin, "after child state change");
|
2004-03-15 19:27:17 +00:00
|
|
|
return;
|
2001-12-04 22:12:50 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2004-08-03 09:51:37 +00:00
|
|
|
GST_LOG_BIN_CONTENTS (bin, "after child state change");
|
2004-07-29 20:33:49 +00:00
|
|
|
GST_UNLOCK (bin);
|
2001-12-04 22:12:50 +00:00
|
|
|
}
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2004-07-12 21:27:11 +00:00
|
|
|
typedef gboolean (*GstBinForeachFunc) (GstBin * bin, GstElement * element,
|
2004-07-11 11:11:37 +00:00
|
|
|
gpointer data);
|
|
|
|
|
2004-07-12 21:27:11 +00:00
|
|
|
/*
|
|
|
|
* gst_bin_foreach:
|
|
|
|
* @bin: bin to traverse
|
|
|
|
* @func: function to call on each child
|
|
|
|
* @data: user data handed to each function call
|
|
|
|
*
|
|
|
|
* Calls @func on each child of the bin. If @func returns FALSE,
|
|
|
|
* gst_bin_foreach() immediately returns.
|
|
|
|
* It is assumed that calling @func may alter the set of @bin's children. @func
|
|
|
|
* will only be called on children that were in @bin when gst_bin_foreach() was
|
|
|
|
* called, and that are still in @bin when the child is reached.
|
|
|
|
*
|
|
|
|
* Returns: TRUE if @func always returned TRUE, FALSE otherwise
|
|
|
|
**/
|
|
|
|
static gboolean
|
2004-07-11 11:11:37 +00:00
|
|
|
gst_bin_foreach (GstBin * bin, GstBinForeachFunc func, gpointer data)
|
|
|
|
{
|
2004-07-12 21:27:11 +00:00
|
|
|
GList *kids, *walk;
|
2004-07-11 11:11:37 +00:00
|
|
|
|
2004-07-12 21:27:11 +00:00
|
|
|
g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
|
|
|
|
g_return_val_if_fail (func != NULL, FALSE);
|
2004-07-11 11:11:37 +00:00
|
|
|
|
2004-07-12 21:27:11 +00:00
|
|
|
kids = g_list_copy (bin->children);
|
2004-07-11 11:11:37 +00:00
|
|
|
|
2004-07-12 21:27:11 +00:00
|
|
|
for (walk = kids; walk; walk = g_list_next (walk)) {
|
|
|
|
GstElement *element = (GstElement *) walk->data;
|
2004-07-11 11:11:37 +00:00
|
|
|
|
2004-07-12 21:27:11 +00:00
|
|
|
if (g_list_find (bin->children, element)) {
|
|
|
|
gboolean res = func (bin, element, data);
|
2004-07-11 11:11:37 +00:00
|
|
|
|
2004-07-12 21:27:11 +00:00
|
|
|
if (!res) {
|
|
|
|
g_list_free (kids);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
2004-07-11 11:11:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
g_list_free (kids);
|
2004-07-12 21:27:11 +00:00
|
|
|
return TRUE;
|
2004-07-11 11:11:37 +00:00
|
|
|
}
|
|
|
|
|
2004-07-12 21:27:11 +00:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
GstElementState pending;
|
|
|
|
GstElementStateReturn result;
|
|
|
|
}
|
|
|
|
SetKidStateData;
|
2004-07-11 11:11:37 +00:00
|
|
|
static int
|
2004-07-12 21:27:11 +00:00
|
|
|
set_kid_state_func (GstBin * bin, GstElement * child, gpointer user_data)
|
2004-07-11 11:11:37 +00:00
|
|
|
{
|
2004-07-12 21:27:11 +00:00
|
|
|
GstElementState old_child_state;
|
|
|
|
SetKidStateData *data = user_data;
|
2004-07-11 11:11:37 +00:00
|
|
|
|
|
|
|
if (GST_FLAG_IS_SET (child, GST_ELEMENT_LOCKED_STATE)) {
|
2004-07-12 21:27:11 +00:00
|
|
|
return TRUE;
|
2004-07-11 11:11:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
old_child_state = GST_STATE (child);
|
|
|
|
|
|
|
|
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
|
2004-07-29 20:33:49 +00:00
|
|
|
"changing state of child %s from current %s to pending %s",
|
2004-07-11 11:11:37 +00:00
|
|
|
GST_ELEMENT_NAME (child), gst_element_state_get_name (old_child_state),
|
2004-07-29 20:33:49 +00:00
|
|
|
gst_element_state_get_name (data->pending));
|
2004-07-11 11:11:37 +00:00
|
|
|
|
2004-07-29 20:33:49 +00:00
|
|
|
switch (gst_element_set_state (child, data->pending)) {
|
2004-07-11 11:11:37 +00:00
|
|
|
case GST_STATE_FAILURE:
|
|
|
|
GST_CAT_INFO_OBJECT (GST_CAT_STATES, bin,
|
|
|
|
"child '%s' failed to go to state %d(%s)",
|
|
|
|
GST_ELEMENT_NAME (child),
|
2004-07-29 20:33:49 +00:00
|
|
|
data->pending, gst_element_state_get_name (data->pending));
|
2004-07-11 11:11:37 +00:00
|
|
|
|
|
|
|
gst_element_set_state (child, old_child_state);
|
2004-07-12 21:27:11 +00:00
|
|
|
return FALSE; /* error out to the caller */
|
2004-07-11 11:11:37 +00:00
|
|
|
|
|
|
|
case GST_STATE_ASYNC:
|
|
|
|
GST_CAT_INFO_OBJECT (GST_CAT_STATES, bin,
|
|
|
|
"child '%s' is changing state asynchronously",
|
|
|
|
GST_ELEMENT_NAME (child));
|
2004-07-29 20:33:49 +00:00
|
|
|
data->result = GST_STATE_ASYNC;
|
2004-07-12 21:27:11 +00:00
|
|
|
return TRUE;
|
2004-07-11 11:11:37 +00:00
|
|
|
|
|
|
|
case GST_STATE_SUCCESS:
|
|
|
|
GST_CAT_DEBUG (GST_CAT_STATES,
|
|
|
|
"child '%s' changed state to %d(%s) successfully",
|
2004-07-29 20:33:49 +00:00
|
|
|
GST_ELEMENT_NAME (child), data->pending,
|
|
|
|
gst_element_state_get_name (data->pending));
|
2004-07-12 21:27:11 +00:00
|
|
|
return TRUE;
|
2004-07-11 11:11:37 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
g_assert_not_reached ();
|
2004-07-12 21:27:11 +00:00
|
|
|
return FALSE; /* satisfy gcc */
|
2004-07-11 11:11:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-07-29 20:33:49 +00:00
|
|
|
static GstElementStateReturn
|
|
|
|
gst_bin_change_state (GstElement * element)
|
2004-07-12 21:27:11 +00:00
|
|
|
{
|
2004-07-29 20:33:49 +00:00
|
|
|
GstBin *bin;
|
|
|
|
GstElementStateReturn ret;
|
|
|
|
GstElementState old_state, pending;
|
gst/gstbin.c: make state changes work correctly and reentrant (so removing elements from bins during state changes of...
Original commit message from CVS:
* gst/gstbin.c: (gst_bin_get_type), (gst_bin_class_init),
(gst_bin_fix_state), (gst_bin_add_func), (gst_bin_remove_func),
(gst_bin_child_state_change_func), (set_kid_state_func),
(gst_bin_set_state), (gst_bin_change_state_norecurse):
make state changes work correctly and reentrant (so removing
elements from bins during state changes of bins doesn't cause
segfaults or even wrong states)
add debugging category and debugging output to print children states
* gst/gstbin.c: (gst_bin_dispose):
add some assertion checks
* gst/gstbin.h:
* gst/gstbin.c: (gst_bin_sync_children_state):
deprecate this function - it just does gst_bin_set_state (bin,
GST_STATE (bin))
* testsuite/threads/queue.c: (main):
don't use gst_bin_sync_children_state anymore
* testsuite/states/Makefile.am:
* testsuite/states/bin.c:
test that the state changes of bins work as expected
* gst/gstthread.c: (gst_thread_class_init), (gst_thread_set_state):
some adjustments to change states correctly, too
* gst/gstthread.c: (gst_thread_change_state):
don't enable/disable "threadsafe" properties, they're unused and
cause random segfaults
* testsuite/threads/Makefile.am:
the queue check randomly passes now, ignore it
2004-07-21 21:28:58 +00:00
|
|
|
SetKidStateData data;
|
2004-07-12 21:27:11 +00:00
|
|
|
|
2004-07-29 20:33:49 +00:00
|
|
|
g_return_val_if_fail (GST_IS_BIN (element), GST_STATE_FAILURE);
|
2004-07-28 10:15:08 +00:00
|
|
|
|
2004-07-29 20:33:49 +00:00
|
|
|
bin = GST_BIN (element);
|
|
|
|
|
|
|
|
old_state = GST_STATE (element);
|
|
|
|
pending = GST_STATE_PENDING (element);
|
|
|
|
|
|
|
|
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
|
|
|
"changing state of children from %s to %s",
|
|
|
|
gst_element_state_get_name (old_state),
|
2004-07-28 10:15:08 +00:00
|
|
|
gst_element_state_get_name (pending));
|
|
|
|
|
2004-07-29 20:33:49 +00:00
|
|
|
if (pending == GST_STATE_VOID_PENDING)
|
|
|
|
return GST_STATE_SUCCESS;
|
2004-07-28 10:15:08 +00:00
|
|
|
|
2004-07-29 20:33:49 +00:00
|
|
|
data.pending = pending;
|
|
|
|
data.result = GST_STATE_SUCCESS;
|
|
|
|
if (!gst_bin_foreach (bin, set_kid_state_func, &data)) {
|
|
|
|
GST_STATE_PENDING (element) = old_state;
|
|
|
|
return GST_STATE_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
|
|
|
"done changing bin's state from %s to %s, now in %s",
|
|
|
|
gst_element_state_get_name (old_state),
|
|
|
|
gst_element_state_get_name (pending),
|
|
|
|
gst_element_state_get_name (GST_STATE (element)));
|
|
|
|
|
|
|
|
if (data.result == GST_STATE_ASYNC)
|
|
|
|
ret = GST_STATE_ASYNC;
|
|
|
|
else {
|
|
|
|
/* FIXME: this should have been done by the children already, no? */
|
|
|
|
if (parent_class->change_state) {
|
|
|
|
ret = parent_class->change_state (element);
|
|
|
|
} else
|
|
|
|
ret = GST_STATE_SUCCESS;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
GstElementStateReturn
|
|
|
|
gst_bin_set_state (GstElement * element, GstElementState state)
|
|
|
|
{
|
|
|
|
GstBin *bin = GST_BIN (element);
|
|
|
|
|
|
|
|
if (GST_STATE (bin) == state) {
|
|
|
|
SetKidStateData data;
|
2004-07-28 10:15:08 +00:00
|
|
|
|
2004-07-29 20:33:49 +00:00
|
|
|
data.pending = state;
|
|
|
|
data.result = GST_STATE_SUCCESS;
|
2004-07-28 10:15:08 +00:00
|
|
|
if (!gst_bin_foreach (bin, set_kid_state_func, &data)) {
|
2004-07-29 20:33:49 +00:00
|
|
|
return GST_STATE_FAILURE;
|
2004-07-28 10:15:08 +00:00
|
|
|
} else {
|
2004-07-29 20:33:49 +00:00
|
|
|
return data.result;
|
2004-07-28 10:15:08 +00:00
|
|
|
}
|
2004-07-29 20:33:49 +00:00
|
|
|
} else {
|
|
|
|
return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, set_state, (element,
|
|
|
|
state), GST_STATE_FAILURE);
|
2004-07-12 21:27:11 +00:00
|
|
|
}
|
|
|
|
}
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2001-01-20 03:10:44 +00:00
|
|
|
static GstElementStateReturn
|
2001-12-15 22:37:35 +00:00
|
|
|
gst_bin_change_state_norecurse (GstBin * bin)
|
2000-11-04 18:54:07 +00:00
|
|
|
{
|
2004-07-29 20:33:49 +00:00
|
|
|
GstElementStateReturn ret;
|
2002-02-03 20:07:09 +00:00
|
|
|
|
2004-07-29 20:33:49 +00:00
|
|
|
if (parent_class->change_state) {
|
|
|
|
GST_CAT_LOG_OBJECT (GST_CAT_STATES, bin, "setting bin's own state");
|
|
|
|
ret = parent_class->change_state (GST_ELEMENT (bin));
|
2002-02-03 20:07:09 +00:00
|
|
|
|
2004-07-29 20:33:49 +00:00
|
|
|
return ret;
|
|
|
|
} else
|
|
|
|
return GST_STATE_FAILURE;
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
|
|
|
|
2001-01-20 03:10:44 +00:00
|
|
|
static void
|
2001-12-15 22:37:35 +00:00
|
|
|
gst_bin_dispose (GObject * object)
|
2000-11-04 18:54:07 +00:00
|
|
|
{
|
|
|
|
GstBin *bin = GST_BIN (object);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2004-05-03 14:45:38 +00:00
|
|
|
GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose");
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2004-07-09 15:03:51 +00:00
|
|
|
gst_element_set_state (GST_ELEMENT (object), GST_STATE_NULL);
|
2002-02-17 19:58:29 +00:00
|
|
|
|
2004-05-06 21:40:55 +00:00
|
|
|
while (bin->children) {
|
|
|
|
gst_bin_remove (bin, GST_ELEMENT (bin->children->data));
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
2004-05-06 21:40:55 +00:00
|
|
|
g_assert (bin->children == NULL);
|
|
|
|
g_assert (bin->numchildren == 0);
|
2001-05-25 21:00:07 +00:00
|
|
|
|
2001-09-28 19:16:02 +00:00
|
|
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
|
|
|
|
2000-03-27 19:53:43 +00:00
|
|
|
/**
|
|
|
|
* gst_bin_get_by_name:
|
|
|
|
* @bin: #Gstbin to search
|
|
|
|
* @name: the element name to search for
|
|
|
|
*
|
2001-01-06 22:05:15 +00:00
|
|
|
* Get the element with the given name from this bin.
|
2000-03-27 19:53:43 +00:00
|
|
|
*
|
|
|
|
* Returns: the element with the given name
|
|
|
|
*/
|
2001-12-15 22:37:35 +00:00
|
|
|
GstElement *
|
|
|
|
gst_bin_get_by_name (GstBin * bin, const gchar * name)
|
2000-11-04 18:54:07 +00:00
|
|
|
{
|
2000-01-30 09:03:00 +00:00
|
|
|
GList *children;
|
|
|
|
GstElement *child;
|
|
|
|
|
2000-11-04 18:54:07 +00:00
|
|
|
g_return_val_if_fail (bin != NULL, NULL);
|
|
|
|
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
|
|
|
|
g_return_val_if_fail (name != NULL, NULL);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2004-03-13 15:27:01 +00:00
|
|
|
GST_CAT_INFO (GST_CAT_PARENTAGE, "[%s]: looking up child element %s",
|
|
|
|
GST_ELEMENT_NAME (bin), name);
|
2000-12-30 02:41:15 +00:00
|
|
|
|
2000-01-30 09:03:00 +00:00
|
|
|
children = bin->children;
|
|
|
|
while (children) {
|
2000-11-04 18:54:07 +00:00
|
|
|
child = GST_ELEMENT (children->data);
|
2001-12-15 22:37:35 +00:00
|
|
|
if (!strcmp (GST_OBJECT_NAME (child), name))
|
2000-01-30 09:03:00 +00:00
|
|
|
return child;
|
2000-11-04 18:54:07 +00:00
|
|
|
if (GST_IS_BIN (child)) {
|
|
|
|
GstElement *res = gst_bin_get_by_name (GST_BIN (child), name);
|
2001-12-15 22:37:35 +00:00
|
|
|
|
2001-01-20 03:10:44 +00:00
|
|
|
if (res)
|
2004-03-15 19:27:17 +00:00
|
|
|
return res;
|
2000-09-27 19:33:10 +00:00
|
|
|
}
|
2000-11-04 18:54:07 +00:00
|
|
|
children = g_list_next (children);
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2001-01-29 00:06:02 +00:00
|
|
|
/**
|
|
|
|
* gst_bin_get_by_name_recurse_up:
|
|
|
|
* @bin: #Gstbin to search
|
|
|
|
* @name: the element name to search for
|
|
|
|
*
|
|
|
|
* Get the element with the given name from this bin. If the
|
|
|
|
* element is not found, a recursion is performed on the parent bin.
|
|
|
|
*
|
|
|
|
* Returns: the element with the given name
|
|
|
|
*/
|
2001-12-15 22:37:35 +00:00
|
|
|
GstElement *
|
|
|
|
gst_bin_get_by_name_recurse_up (GstBin * bin, const gchar * name)
|
2001-01-29 00:06:02 +00:00
|
|
|
{
|
|
|
|
GstElement *result = NULL;
|
|
|
|
GstObject *parent;
|
|
|
|
|
|
|
|
g_return_val_if_fail (bin != NULL, NULL);
|
|
|
|
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
|
|
|
|
g_return_val_if_fail (name != NULL, NULL);
|
|
|
|
|
|
|
|
result = gst_bin_get_by_name (bin, name);
|
|
|
|
|
2001-12-15 22:37:35 +00:00
|
|
|
if (!result) {
|
|
|
|
parent = gst_object_get_parent (GST_OBJECT (bin));
|
2001-01-29 00:06:02 +00:00
|
|
|
|
2001-12-15 22:37:35 +00:00
|
|
|
if (parent && GST_IS_BIN (parent)) {
|
|
|
|
result = gst_bin_get_by_name_recurse_up (GST_BIN (parent), name);
|
|
|
|
}
|
2001-01-29 00:06:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2000-03-27 19:53:43 +00:00
|
|
|
/**
|
|
|
|
* gst_bin_get_list:
|
|
|
|
* @bin: #Gstbin to get the list from
|
|
|
|
*
|
2001-01-06 22:05:15 +00:00
|
|
|
* Get the list of elements in this bin.
|
2000-03-27 19:53:43 +00:00
|
|
|
*
|
|
|
|
* Returns: a GList of elements
|
|
|
|
*/
|
2002-04-19 19:49:41 +00:00
|
|
|
const GList *
|
2001-12-15 22:37:35 +00:00
|
|
|
gst_bin_get_list (GstBin * bin)
|
2000-11-04 18:54:07 +00:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
|
|
|
return bin->children;
|
|
|
|
}
|
|
|
|
|
2003-12-16 19:35:26 +00:00
|
|
|
/**
|
|
|
|
* gst_bin_get_by_interface:
|
|
|
|
* @bin: bin to find element in
|
|
|
|
* @interface: interface to be implemented by interface
|
|
|
|
*
|
2004-07-09 08:45:18 +00:00
|
|
|
* Looks for the first element inside the bin that implements the given
|
2003-12-16 19:35:26 +00:00
|
|
|
* interface. If such an element is found, it returns the element. You can
|
|
|
|
* cast this element to the given interface afterwards.
|
2004-07-09 08:45:18 +00:00
|
|
|
* If you want all elements that implement the interface, use
|
2003-12-16 19:35:26 +00:00
|
|
|
* gst_bin_get_all_by_interface(). The function recurses bins inside bins.
|
|
|
|
*
|
|
|
|
* Returns: An element inside the bin implementing the interface.
|
|
|
|
*/
|
|
|
|
GstElement *
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_bin_get_by_interface (GstBin * bin, GType interface)
|
2003-12-16 19:35:26 +00:00
|
|
|
{
|
|
|
|
GList *walk;
|
2004-03-13 15:27:01 +00:00
|
|
|
|
2003-12-16 19:35:26 +00:00
|
|
|
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
|
|
|
|
g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface), NULL);
|
|
|
|
|
|
|
|
walk = bin->children;
|
|
|
|
while (walk) {
|
|
|
|
if (G_TYPE_CHECK_INSTANCE_TYPE (walk->data, interface))
|
|
|
|
return GST_ELEMENT (walk->data);
|
|
|
|
if (GST_IS_BIN (walk->data)) {
|
|
|
|
GstElement *ret;
|
2004-03-13 15:27:01 +00:00
|
|
|
|
2003-12-16 19:35:26 +00:00
|
|
|
ret = gst_bin_get_by_interface (GST_BIN (walk->data), interface);
|
|
|
|
if (ret)
|
2004-03-15 19:27:17 +00:00
|
|
|
return ret;
|
2003-12-16 19:35:26 +00:00
|
|
|
}
|
|
|
|
walk = g_list_next (walk);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_bin_get_all_by_interface:
|
|
|
|
* @bin: bin to find elements in
|
|
|
|
* @interface: interface to be implemented by interface
|
|
|
|
*
|
2004-07-09 08:45:18 +00:00
|
|
|
* Looks for all elements inside the bin that implements the given
|
2003-12-16 19:35:26 +00:00
|
|
|
* interface. You can safely cast all returned elements to the given interface.
|
2004-07-09 08:45:18 +00:00
|
|
|
* The function recurses bins inside bins. You need to free the list using
|
2003-12-16 19:35:26 +00:00
|
|
|
* g_list_free() after use.
|
|
|
|
*
|
|
|
|
* Returns: An element inside the bin implementing the interface.
|
|
|
|
*/
|
|
|
|
GList *
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_bin_get_all_by_interface (GstBin * bin, GType interface)
|
2003-12-16 19:35:26 +00:00
|
|
|
{
|
|
|
|
GList *walk, *ret = NULL;
|
2004-03-13 15:27:01 +00:00
|
|
|
|
2003-12-16 19:35:26 +00:00
|
|
|
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
|
|
|
|
g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface), NULL);
|
|
|
|
|
|
|
|
walk = bin->children;
|
|
|
|
while (walk) {
|
2004-07-09 08:45:18 +00:00
|
|
|
if (G_TYPE_CHECK_INSTANCE_TYPE (walk->data, interface)) {
|
|
|
|
GST_DEBUG_OBJECT (bin, "element %s implements requested interface",
|
|
|
|
GST_ELEMENT_NAME (GST_ELEMENT (walk->data)));
|
2003-12-16 19:35:26 +00:00
|
|
|
ret = g_list_prepend (ret, walk->data);
|
2004-07-09 08:45:18 +00:00
|
|
|
}
|
2003-12-16 19:35:26 +00:00
|
|
|
if (GST_IS_BIN (walk->data)) {
|
2004-03-13 15:27:01 +00:00
|
|
|
ret = g_list_concat (ret,
|
2004-03-15 19:27:17 +00:00
|
|
|
gst_bin_get_all_by_interface (GST_BIN (walk->data), interface));
|
2003-12-16 19:35:26 +00:00
|
|
|
}
|
|
|
|
walk = g_list_next (walk);
|
|
|
|
}
|
|
|
|
|
2004-03-13 15:27:01 +00:00
|
|
|
return ret;
|
2003-12-16 19:35:26 +00:00
|
|
|
}
|
|
|
|
|
2003-04-18 23:34:21 +00:00
|
|
|
/**
|
|
|
|
* gst_bin_sync_children_state:
|
|
|
|
* @bin: #Gstbin to sync state
|
|
|
|
*
|
|
|
|
* Tries to set the state of the children of this bin to the same state of the
|
|
|
|
* bin by calling gst_element_set_state for each child not already having a
|
|
|
|
* synchronized state.
|
|
|
|
*
|
|
|
|
* Returns: The worst return value of any gst_element_set_state. So if one child
|
|
|
|
* returns #GST_STATE_FAILURE while all others return #GST_STATE_SUCCESS
|
|
|
|
* this function returns #GST_STATE_FAILURE.
|
|
|
|
*/
|
|
|
|
GstElementStateReturn
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_bin_sync_children_state (GstBin * bin)
|
2003-04-18 23:34:21 +00:00
|
|
|
{
|
2004-07-29 20:33:49 +00:00
|
|
|
GList *children;
|
|
|
|
GstElement *element;
|
|
|
|
GstElementState state;
|
|
|
|
GstElementStateReturn ret = GST_STATE_SUCCESS;
|
|
|
|
|
2003-04-18 23:34:21 +00:00
|
|
|
g_return_val_if_fail (GST_IS_BIN (bin), GST_STATE_FAILURE);
|
|
|
|
|
2004-07-29 20:33:49 +00:00
|
|
|
state = GST_STATE (bin);
|
|
|
|
children = bin->children;
|
|
|
|
GST_CAT_INFO (GST_CAT_STATES,
|
|
|
|
"syncing state of children with bin \"%s\"'s state %s",
|
|
|
|
GST_ELEMENT_NAME (bin), gst_element_state_get_name (state));
|
|
|
|
|
|
|
|
while (children) {
|
|
|
|
element = GST_ELEMENT (children->data);
|
|
|
|
children = children->next;
|
|
|
|
if (GST_STATE (element) != state) {
|
|
|
|
switch (gst_element_set_state (element, state)) {
|
|
|
|
case GST_STATE_SUCCESS:
|
|
|
|
break;
|
|
|
|
case GST_STATE_ASYNC:
|
|
|
|
if (ret == GST_STATE_SUCCESS)
|
|
|
|
ret = GST_STATE_ASYNC;
|
|
|
|
break;
|
|
|
|
case GST_STATE_FAILURE:
|
|
|
|
ret = GST_STATE_FAILURE;
|
|
|
|
default:
|
|
|
|
/* make sure gst_element_set_state never returns this */
|
|
|
|
g_assert_not_reached ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2003-04-18 23:34:21 +00:00
|
|
|
}
|
2004-03-13 15:27:01 +00:00
|
|
|
|
2001-06-25 06:45:56 +00:00
|
|
|
#ifndef GST_DISABLE_LOADSAVE
|
2001-01-20 03:10:44 +00:00
|
|
|
static xmlNodePtr
|
2001-12-15 22:37:35 +00:00
|
|
|
gst_bin_save_thyself (GstObject * object, xmlNodePtr parent)
|
2000-11-04 18:54:07 +00:00
|
|
|
{
|
2001-01-29 00:06:02 +00:00
|
|
|
GstBin *bin = GST_BIN (object);
|
|
|
|
xmlNodePtr childlist, elementnode;
|
2000-01-30 09:03:00 +00:00
|
|
|
GList *children;
|
|
|
|
GstElement *child;
|
|
|
|
|
2001-01-29 00:06:02 +00:00
|
|
|
if (GST_OBJECT_CLASS (parent_class)->save_thyself)
|
|
|
|
GST_OBJECT_CLASS (parent_class)->save_thyself (GST_OBJECT (bin), parent);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2001-01-29 00:06:02 +00:00
|
|
|
childlist = xmlNewChild (parent, NULL, "children", NULL);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2004-03-13 15:27:01 +00:00
|
|
|
GST_CAT_INFO (GST_CAT_XML, "[%s]: saving %d children",
|
|
|
|
GST_ELEMENT_NAME (bin), bin->numchildren);
|
2000-12-30 02:41:15 +00:00
|
|
|
|
2000-01-30 09:03:00 +00:00
|
|
|
children = bin->children;
|
|
|
|
while (children) {
|
2000-11-04 18:54:07 +00:00
|
|
|
child = GST_ELEMENT (children->data);
|
2001-01-29 00:06:02 +00:00
|
|
|
elementnode = xmlNewChild (childlist, NULL, "element", NULL);
|
|
|
|
gst_object_save_thyself (GST_OBJECT (child), elementnode);
|
2000-11-04 18:54:07 +00:00
|
|
|
children = g_list_next (children);
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
2000-09-27 19:33:10 +00:00
|
|
|
return childlist;
|
|
|
|
}
|
|
|
|
|
2001-01-20 03:10:44 +00:00
|
|
|
static void
|
2001-12-15 22:37:35 +00:00
|
|
|
gst_bin_restore_thyself (GstObject * object, xmlNodePtr self)
|
2000-11-04 18:54:07 +00:00
|
|
|
{
|
2001-01-29 00:06:02 +00:00
|
|
|
GstBin *bin = GST_BIN (object);
|
|
|
|
xmlNodePtr field = self->xmlChildrenNode;
|
2000-09-27 19:33:10 +00:00
|
|
|
xmlNodePtr childlist;
|
|
|
|
|
|
|
|
while (field) {
|
2000-11-04 18:54:07 +00:00
|
|
|
if (!strcmp (field->name, "children")) {
|
2004-03-13 15:27:01 +00:00
|
|
|
GST_CAT_INFO (GST_CAT_XML, "[%s]: loading children",
|
2004-03-15 19:27:17 +00:00
|
|
|
GST_ELEMENT_NAME (object));
|
2001-01-18 11:16:53 +00:00
|
|
|
childlist = field->xmlChildrenNode;
|
2000-09-27 19:33:10 +00:00
|
|
|
while (childlist) {
|
2004-03-15 19:27:17 +00:00
|
|
|
if (!strcmp (childlist->name, "element")) {
|
|
|
|
GstElement *element =
|
|
|
|
gst_xml_make_element (childlist, GST_OBJECT (bin));
|
|
|
|
|
|
|
|
/* it had to be parented to find the pads, now we ref and unparent so
|
|
|
|
* we can add it to the bin */
|
|
|
|
gst_object_ref (GST_OBJECT (element));
|
|
|
|
gst_object_unparent (GST_OBJECT (element));
|
|
|
|
|
|
|
|
gst_bin_add (bin, element);
|
|
|
|
}
|
|
|
|
childlist = childlist->next;
|
2000-09-27 19:33:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
field = field->next;
|
|
|
|
}
|
2004-07-04 10:26:24 +00:00
|
|
|
if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
|
|
|
|
(GST_OBJECT_CLASS (parent_class)->restore_thyself) (object, self);
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
2001-10-17 10:21:27 +00:00
|
|
|
#endif /* GST_DISABLE_LOADSAVE */
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2001-12-04 22:12:50 +00:00
|
|
|
static gboolean
|
2001-12-15 22:37:35 +00:00
|
|
|
gst_bin_iterate_func (GstBin * bin)
|
2001-12-04 22:12:50 +00:00
|
|
|
{
|
2004-05-18 21:18:43 +00:00
|
|
|
GstScheduler *sched = GST_ELEMENT_SCHED (bin);
|
|
|
|
|
2001-12-14 22:59:21 +00:00
|
|
|
/* only iterate if this is the manager bin */
|
2004-05-18 21:18:43 +00:00
|
|
|
if (sched && sched->parent == GST_ELEMENT (bin)) {
|
2001-12-24 15:14:03 +00:00
|
|
|
GstSchedulerState state;
|
|
|
|
|
2004-05-18 21:18:43 +00:00
|
|
|
state = gst_scheduler_iterate (sched);
|
2001-12-24 15:14:03 +00:00
|
|
|
|
|
|
|
if (state == GST_SCHEDULER_STATE_RUNNING) {
|
|
|
|
return TRUE;
|
2004-03-13 15:27:01 +00:00
|
|
|
} else if (state == GST_SCHEDULER_STATE_ERROR) {
|
2001-12-24 15:14:03 +00:00
|
|
|
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED);
|
2004-05-18 21:18:43 +00:00
|
|
|
} else if (state == GST_SCHEDULER_STATE_STOPPED) {
|
|
|
|
/* check if we have children scheds that are still running */
|
|
|
|
/* FIXME: remove in 0.9? autouseless because iterations gone? */
|
|
|
|
GList *walk;
|
|
|
|
|
|
|
|
for (walk = sched->schedulers; walk; walk = g_list_next (walk)) {
|
|
|
|
GstScheduler *test = walk->data;
|
|
|
|
|
|
|
|
g_return_val_if_fail (test->parent, FALSE);
|
|
|
|
if (GST_STATE (test->parent) == GST_STATE_PLAYING) {
|
|
|
|
GST_CAT_DEBUG_OBJECT (GST_CAT_SCHEDULING, bin,
|
|
|
|
"current bin is not iterating, but children are, "
|
|
|
|
"so returning TRUE anyway...");
|
|
|
|
g_usleep (1);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
2001-12-24 15:14:03 +00:00
|
|
|
}
|
2004-03-13 15:27:01 +00:00
|
|
|
} else {
|
|
|
|
g_warning ("bin \"%s\" is not the managing bin, can't be iterated on!\n",
|
2004-03-15 19:27:17 +00:00
|
|
|
GST_ELEMENT_NAME (bin));
|
2001-12-04 22:12:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
2000-08-14 10:55:35 +00:00
|
|
|
|
2000-03-27 19:53:43 +00:00
|
|
|
/**
|
|
|
|
* gst_bin_iterate:
|
2002-09-12 18:55:21 +00:00
|
|
|
* @bin: a#GstBin to iterate.
|
2000-03-27 19:53:43 +00:00
|
|
|
*
|
2001-01-06 22:05:15 +00:00
|
|
|
* Iterates over the elements in this bin.
|
2001-01-21 23:20:46 +00:00
|
|
|
*
|
2002-09-12 18:55:21 +00:00
|
|
|
* Returns: TRUE if the bin did something useful. This value
|
2001-01-21 23:20:46 +00:00
|
|
|
* can be used to determine it the bin is in EOS.
|
2000-03-27 19:53:43 +00:00
|
|
|
*/
|
2001-01-20 17:59:25 +00:00
|
|
|
gboolean
|
2004-03-13 15:27:01 +00:00
|
|
|
gst_bin_iterate (GstBin * bin)
|
2000-11-04 18:54:07 +00:00
|
|
|
{
|
2003-10-14 00:00:37 +00:00
|
|
|
gboolean running;
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2002-03-18 04:41:37 +00:00
|
|
|
g_return_val_if_fail (bin != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
|
|
|
|
|
gst/elements/gstfilesrc.c: compute mapsize correctly
Original commit message from CVS:
* gst/elements/gstfilesrc.c: (gst_filesrc_get_mmap):
compute mapsize correctly
* gst/elements/gstfilesrc.c: (gst_filesrc_get_mmap):
use correct datatypes when calling a varargs function
* gst/elements/gsttypefindelement.c: (stop_typefinding):
push a DISCONT event as first thing
* gst/gst_private.h:
* gst/gstinfo.c: (_gst_debug_init):
remove GST_DATAFLOW debugging category
* gst/gstbin.c: (gst_bin_iterate):
use GST_SCHEDULING category
* gst/gstpad.c: (gst_pad_get_type), (_invent_event),
(gst_pad_push), (gst_pad_pull), (gst_pad_call_chain_function),
(gst_pad_call_get_function):
add GST_DATAFLOW to easily track flow of buffers or events.
* gst/gstqueue.c: (gst_queue_get_type),
(gst_queue_handle_pending_events), (gst_queue_chain),
(gst_queue_get), (gst_queue_handle_src_event):
use own static debugging category GST_DATAFLOW for dataflow,
use DEBUG category for showing which path events go, use LOG
category for buffers.
2004-05-11 16:20:41 +00:00
|
|
|
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, bin, "starting iteration");
|
2003-02-27 18:18:32 +00:00
|
|
|
gst_object_ref (GST_OBJECT (bin));
|
|
|
|
|
2003-10-14 00:00:37 +00:00
|
|
|
running = FALSE;
|
|
|
|
g_signal_emit (G_OBJECT (bin), gst_bin_signals[ITERATE], 0, &running);
|
2002-06-10 16:48:47 +00:00
|
|
|
|
2003-02-27 18:18:32 +00:00
|
|
|
gst_object_unref (GST_OBJECT (bin));
|
2004-05-18 21:18:43 +00:00
|
|
|
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, bin, "finished iteration");
|
2001-11-14 21:06:15 +00:00
|
|
|
|
|
|
|
return running;
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|