gst/gstelement.c: virutalize gst_element_set_state, use set_state member in class struct that was already added in 0....

Original commit message from CVS:
* gst/gstelement.c: (gst_element_class_init),
(gst_element_set_state), (gst_element_set_state_func):
virutalize gst_element_set_state, use set_state member in class
struct that was already added in 0.7 for this.
* gst/gstbin.c: (gst_bin_foreach), (set_kid_state_func),
(gst_bin_change_state):
make gst_bin_foreach works similar to other foreach functions, plug
memleaks in it. Make functions using it work with the new approach.
Document gst_bin_foreach, so it can be exported if we want to
* gst/gstbin.c: (gst_bin_class_init), (gst_bin_set_state):
use virtualized set_state to make set_state on bins set the state of
all its children.
This commit is contained in:
Benjamin Otte 2004-07-12 21:27:11 +00:00
parent 2ab9d39848
commit d77dbaac2f
3 changed files with 115 additions and 80 deletions

View file

@ -1,3 +1,18 @@
2004-07-12 Benjamin Otte <otte@gnome.org>
* gst/gstelement.c: (gst_element_class_init),
(gst_element_set_state), (gst_element_set_state_func):
virutalize gst_element_set_state, use set_state member in class
struct that was already added in 0.7 for this.
* gst/gstbin.c: (gst_bin_foreach), (set_kid_state_func),
(gst_bin_change_state):
make gst_bin_foreach works similar to other foreach functions, plug
memleaks in it. Make functions using it work with the new approach.
Document gst_bin_foreach, so it can be exported if we want to
* gst/gstbin.c: (gst_bin_class_init), (gst_bin_set_state):
use virtualized set_state to make set_state on bins set the state of
all its children.
2004-07-12 Benjamin Otte <otte@gnome.org> 2004-07-12 Benjamin Otte <otte@gnome.org>
* configure.ac: * configure.ac:

View file

@ -32,6 +32,7 @@
#include "gstscheduler.h" #include "gstscheduler.h"
#include "gstindex.h" #include "gstindex.h"
#include "gstutils.h"
static GstElementDetails gst_bin_details = GST_ELEMENT_DETAILS ("Generic bin", static GstElementDetails gst_bin_details = GST_ELEMENT_DETAILS ("Generic bin",
"Generic/Bin", "Generic/Bin",
@ -56,6 +57,8 @@ static void gst_bin_add_func (GstBin * bin, GstElement * element);
static void gst_bin_remove_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, static void gst_bin_child_state_change_func (GstBin * bin,
GstElementState oldstate, GstElementState newstate, GstElement * child); GstElementState oldstate, GstElementState newstate, GstElement * child);
GstElementStateReturn gst_bin_set_state (GstElement * element,
GstElementState state);
static GstClock *gst_bin_get_clock_func (GstElement * element); static GstClock *gst_bin_get_clock_func (GstElement * element);
static void gst_bin_set_clock_func (GstElement * element, GstClock * clock); static void gst_bin_set_clock_func (GstElement * element, GstClock * clock);
@ -161,6 +164,7 @@ gst_bin_class_init (GstBinClass * klass)
#endif #endif
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_bin_change_state); gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_bin_change_state);
gstelement_class->set_state = GST_DEBUG_FUNCPTR (gst_bin_set_state);
#ifndef GST_DISABLE_INDEX #ifndef GST_DISABLE_INDEX
gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_bin_set_index); gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_bin_set_index);
#endif #endif
@ -707,57 +711,64 @@ gst_bin_child_state_change_func (GstBin * bin, GstElementState oldstate,
GST_UNLOCK (bin); GST_UNLOCK (bin);
} }
typedef gint (*GstBinForeachFunc) (GstBin * bin, GstElement * element, typedef gboolean (*GstBinForeachFunc) (GstBin * bin, GstElement * element,
gpointer data); gpointer data);
/* Call FUNC on each child of BIN, in the order that they are in bin->children. /*
* gst_bin_foreach:
It is assumed that calling FUNC may alter the set of BIN's children. FUNC * @bin: bin to traverse
will only be called on children that were in BIN when the gst_bin_foreach was * @func: function to call on each child
called, and that are still in BIN when the child is reached. * @data: user data handed to each function call
*
The return value semantics are a bit odd in this one: * Calls @func on each child of the bin. If @func returns FALSE,
* gst_bin_foreach() immediately returns.
If FUNC returns a nonnegative number, the number is added on to the eventual * It is assumed that calling @func may alter the set of @bin's children. @func
return value of gst_bin_foreach, which starts at 0. * 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.
If any FUNC returns a negative number, that value is immediately returned to *
the caller. In that case, the child list might only be partially traversed. * Returns: TRUE if @func always returned TRUE, FALSE otherwise
*/ **/
static gint static gboolean
gst_bin_foreach (GstBin * bin, GstBinForeachFunc func, gpointer data) gst_bin_foreach (GstBin * bin, GstBinForeachFunc func, gpointer data)
{ {
gint sum = 0; GList *kids, *walk;
GList *kids = g_list_copy (bin->children);
while (kids) { g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
GstElement *element = (GstElement *) kids->data; g_return_val_if_fail (func != NULL, FALSE);
gint res = 0;
if (g_list_find (bin->children, element)) kids = g_list_copy (bin->children);
res = func (bin, element, data);
if (res < 0) for (walk = kids; walk; walk = g_list_next (walk)) {
return res; GstElement *element = (GstElement *) walk->data;
sum += res; if (g_list_find (bin->children, element)) {
gboolean res = func (bin, element, data);
kids = kids->next; if (!res) {
g_list_free (kids);
return FALSE;
}
}
} }
g_list_free (kids); g_list_free (kids);
return sum; return TRUE;
} }
static int typedef struct
set_kid_state_func (GstBin * bin, GstElement * child, gpointer data)
{ {
GstElementState old_child_state, pending; GstElementState pending;
GstElementStateReturn result;
pending = (GstElementState) (GPOINTER_TO_INT (data)); }
SetKidStateData;
static int
set_kid_state_func (GstBin * bin, GstElement * child, gpointer user_data)
{
GstElementState old_child_state;
SetKidStateData *data = user_data;
if (GST_FLAG_IS_SET (child, GST_ELEMENT_LOCKED_STATE)) { if (GST_FLAG_IS_SET (child, GST_ELEMENT_LOCKED_STATE)) {
return 0; return TRUE;
} }
old_child_state = GST_STATE (child); old_child_state = GST_STATE (child);
@ -765,34 +776,35 @@ set_kid_state_func (GstBin * bin, GstElement * child, gpointer data)
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin, GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
"changing state of child %s from current %s to pending %s", "changing state of child %s from current %s to pending %s",
GST_ELEMENT_NAME (child), gst_element_state_get_name (old_child_state), GST_ELEMENT_NAME (child), gst_element_state_get_name (old_child_state),
gst_element_state_get_name (pending)); gst_element_state_get_name (data->pending));
switch (gst_element_set_state (child, pending)) { switch (gst_element_set_state (child, data->pending)) {
case GST_STATE_FAILURE: case GST_STATE_FAILURE:
GST_CAT_INFO_OBJECT (GST_CAT_STATES, bin, GST_CAT_INFO_OBJECT (GST_CAT_STATES, bin,
"child '%s' failed to go to state %d(%s)", "child '%s' failed to go to state %d(%s)",
GST_ELEMENT_NAME (child), GST_ELEMENT_NAME (child),
pending, gst_element_state_get_name (pending)); data->pending, gst_element_state_get_name (data->pending));
gst_element_set_state (child, old_child_state); gst_element_set_state (child, old_child_state);
return -1; /* error out to the caller */ return FALSE; /* error out to the caller */
case GST_STATE_ASYNC: case GST_STATE_ASYNC:
GST_CAT_INFO_OBJECT (GST_CAT_STATES, bin, GST_CAT_INFO_OBJECT (GST_CAT_STATES, bin,
"child '%s' is changing state asynchronously", "child '%s' is changing state asynchronously",
GST_ELEMENT_NAME (child)); GST_ELEMENT_NAME (child));
return 1; data->result = GST_STATE_ASYNC;
return TRUE;
case GST_STATE_SUCCESS: case GST_STATE_SUCCESS:
GST_CAT_DEBUG (GST_CAT_STATES, GST_CAT_DEBUG (GST_CAT_STATES,
"child '%s' changed state to %d(%s) successfully", "child '%s' changed state to %d(%s) successfully",
GST_ELEMENT_NAME (child), pending, GST_ELEMENT_NAME (child), data->pending,
gst_element_state_get_name (pending)); gst_element_state_get_name (data->pending));
return 0; return TRUE;
default: default:
g_assert_not_reached (); g_assert_not_reached ();
return -1; /* satisfy gcc */ return FALSE; /* satisfy gcc */
} }
} }
@ -802,8 +814,7 @@ gst_bin_change_state (GstElement * element)
GstBin *bin; GstBin *bin;
GstElementStateReturn ret; GstElementStateReturn ret;
GstElementState old_state, pending; GstElementState old_state, pending;
gint transition, kid_return; SetKidStateData data;
gboolean have_async = FALSE;
g_return_val_if_fail (GST_IS_BIN (element), GST_STATE_FAILURE); g_return_val_if_fail (GST_IS_BIN (element), GST_STATE_FAILURE);
@ -811,7 +822,6 @@ gst_bin_change_state (GstElement * element)
old_state = GST_STATE (element); old_state = GST_STATE (element);
pending = GST_STATE_PENDING (element); pending = GST_STATE_PENDING (element);
transition = GST_STATE_TRANSITION (element);
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
"changing state of children from %s to %s", "changing state of children from %s to %s",
@ -821,15 +831,11 @@ gst_bin_change_state (GstElement * element)
if (pending == GST_STATE_VOID_PENDING) if (pending == GST_STATE_VOID_PENDING)
return GST_STATE_SUCCESS; return GST_STATE_SUCCESS;
kid_return = gst_bin_foreach (bin, set_kid_state_func, data.pending = pending;
GINT_TO_POINTER ((int) pending)); data.result = GST_STATE_SUCCESS;
if (!gst_bin_foreach (bin, set_kid_state_func, &data)) {
/* see gst_bin_foreach return value semantics above */
if (kid_return < 0) {
GST_STATE_PENDING (element) = old_state; GST_STATE_PENDING (element) = old_state;
return GST_STATE_FAILURE; return GST_STATE_FAILURE;
} else if (kid_return > 0) {
have_async = TRUE;
} }
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
@ -838,9 +844,10 @@ gst_bin_change_state (GstElement * element)
gst_element_state_get_name (pending), gst_element_state_get_name (pending),
gst_element_state_get_name (GST_STATE (element))); gst_element_state_get_name (GST_STATE (element)));
if (have_async) if (data.result == GST_STATE_ASYNC)
ret = GST_STATE_ASYNC; ret = GST_STATE_ASYNC;
else { else {
/* FIXME: this should have been done by the children already, no? */
if (parent_class->change_state) { if (parent_class->change_state) {
ret = parent_class->change_state (element); ret = parent_class->change_state (element);
} else } else
@ -849,6 +856,26 @@ gst_bin_change_state (GstElement * element)
return ret; return ret;
} }
GstElementStateReturn
gst_bin_set_state (GstElement * element, GstElementState state)
{
GstBin *bin = GST_BIN (element);
if (GST_STATE (bin) == state) {
SetKidStateData data;
data.pending = state;
data.result = GST_STATE_SUCCESS;
if (!gst_bin_foreach (bin, set_kid_state_func, &data)) {
return GST_STATE_FAILURE;
} else {
return data.result;
}
} else {
return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, set_state, (element,
state), GST_STATE_FAILURE);
}
}
static GstElementStateReturn static GstElementStateReturn
gst_bin_change_state_norecurse (GstBin * bin) gst_bin_change_state_norecurse (GstBin * bin)

View file

@ -76,6 +76,8 @@ static void gst_element_error_func (GstElement * element, GstElement * source,
GError * error, gchar * debug); GError * error, gchar * debug);
static void gst_element_found_tag_func (GstElement * element, static void gst_element_found_tag_func (GstElement * element,
GstElement * source, const GstTagList * tag_list); GstElement * source, const GstTagList * tag_list);
GstElementStateReturn gst_element_set_state_func (GstElement * element,
GstElementState state);
#ifndef GST_DISABLE_LOADSAVE #ifndef GST_DISABLE_LOADSAVE
static xmlNodePtr gst_element_save_thyself (GstObject * object, static xmlNodePtr gst_element_save_thyself (GstObject * object,
@ -170,6 +172,7 @@ gst_element_class_init (GstElementClass * klass)
klass->error = GST_DEBUG_FUNCPTR (gst_element_error_func); klass->error = GST_DEBUG_FUNCPTR (gst_element_error_func);
klass->found_tag = GST_DEBUG_FUNCPTR (gst_element_found_tag_func); klass->found_tag = GST_DEBUG_FUNCPTR (gst_element_found_tag_func);
klass->numpadtemplates = 0; klass->numpadtemplates = 0;
klass->set_state = GST_DEBUG_FUNCPTR (gst_element_set_state_func);
klass->elementfactory = NULL; klass->elementfactory = NULL;
} }
@ -2719,43 +2722,33 @@ gst_element_wait_state_change (GstElement * element)
*/ */
GstElementStateReturn GstElementStateReturn
gst_element_set_state (GstElement * element, GstElementState state) gst_element_set_state (GstElement * element, GstElementState state)
{
GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
klass = GST_ELEMENT_GET_CLASS (element);
/* a set_state function is mandatory */
g_return_val_if_fail (klass->set_state, GST_STATE_FAILURE);
return klass->set_state (element, state);
}
GstElementStateReturn
gst_element_set_state_func (GstElement * element, GstElementState state)
{ {
GstElementClass *oclass; GstElementClass *oclass;
GstElementState curpending; GstElementState curpending;
GstElementStateReturn return_val = GST_STATE_SUCCESS; GstElementStateReturn return_val = GST_STATE_SUCCESS;
g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
oclass = GST_ELEMENT_GET_CLASS (element); oclass = GST_ELEMENT_GET_CLASS (element);
/* for bins, we allow calls to change_state where old == new
* for elements, too many of them break with g_assert_not_reached(),
* so weed those out first. This is done in gst-plugins CVS and can
* be fixed here after a new plugins release.
* FIXME: of course this file should not have ties to gstbin.h *at all*,
* but someone else added a function at the bottom using it.
* Fix this properly for 0.9 */
/* start with the current state */ /* start with the current state */
curpending = GST_STATE (element); curpending = GST_STATE (element);
if (state == curpending) { if (state == curpending) {
if (GST_IS_BIN (element)) { GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
/* set current state on it again */ "element is already in requested state %s, returning",
GST_STATE_PENDING (element) = curpending; gst_element_state_get_name (state));
GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, return GST_STATE_SUCCESS;
"%s is a bin, calling class state change on it for %s -> %s",
GST_OBJECT_NAME (element),
gst_element_state_get_name (curpending),
gst_element_state_get_name (state));
if (oclass->change_state)
return_val = (oclass->change_state) (element);
return return_val;
} else {
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
"non-bin element is already in requested state %s, returning",
gst_element_state_get_name (state));
return GST_STATE_SUCCESS;
}
} }
GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "setting state from %s to %s", GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "setting state from %s to %s",