gst/: Patch state changes according to design document.

Original commit message from CVS:
* gst/gstbin.c: (gst_bin_set_index), (gst_bin_set_clock),
(gst_bin_set_bus), (gst_bin_set_scheduler), (gst_bin_add_func),
(gst_bin_iterate_elements), (gst_bin_get_state),
(gst_bin_change_state), (gst_bin_get_by_name_recurse_up):
* gst/gstelement.c: (gst_element_add_pad),
(gst_element_remove_pad), (gst_element_get_state_func),
(gst_element_get_state), (gst_element_abort_state),
(gst_element_set_state), (gst_element_pads_activate):
* gst/gstelement.h:
Patch state changes according to design document.
This commit is contained in:
Wim Taymans 2005-01-12 18:54:42 +00:00
parent faeeed3dba
commit 83156b4a9d
4 changed files with 104 additions and 66 deletions

View file

@ -1,3 +1,16 @@
2005-01-12 Wim Taymans <wim@fluendo.com>
* gst/gstbin.c: (gst_bin_set_index), (gst_bin_set_clock),
(gst_bin_set_bus), (gst_bin_set_scheduler), (gst_bin_add_func),
(gst_bin_iterate_elements), (gst_bin_get_state),
(gst_bin_change_state), (gst_bin_get_by_name_recurse_up):
* gst/gstelement.c: (gst_element_add_pad),
(gst_element_remove_pad), (gst_element_get_state_func),
(gst_element_get_state), (gst_element_abort_state),
(gst_element_set_state), (gst_element_pads_activate):
* gst/gstelement.h:
Patch state changes according to design document.
2005-01-11 Wim Taymans <wim@fluendo.com> 2005-01-11 Wim Taymans <wim@fluendo.com>
* configure.ac: * configure.ac:

View file

@ -53,7 +53,7 @@ GType _gst_bin_type = 0;
static void gst_bin_dispose (GObject * object); static void gst_bin_dispose (GObject * object);
static GstElementStateReturn gst_bin_change_state (GstElement * element); static GstElementStateReturn gst_bin_change_state (GstElement * element);
static gboolean gst_bin_get_state (GstElement * element, static GstElementStateReturn gst_bin_get_state (GstElement * element,
GstElementState * state, GstElementState * pending, GTimeVal * timeout); GstElementState * state, GstElementState * pending, GTimeVal * timeout);
#ifndef GST_DISABLE_INDEX #ifndef GST_DISABLE_INDEX
@ -645,12 +645,12 @@ gst_bin_iterate_sinks (GstBin * bin)
* *
* MT safe * MT safe
*/ */
static gboolean static GstElementStateReturn
gst_bin_get_state (GstElement * element, GstElementState * state, gst_bin_get_state (GstElement * element, GstElementState * state,
GstElementState * pending, GTimeVal * timeout) GstElementState * pending, GTimeVal * timeout)
{ {
GstBin *bin = GST_BIN (element); GstBin *bin = GST_BIN (element);
gboolean ret; GstElementStateReturn ret;
GList *children; GList *children;
guint32 children_cookie; guint32 children_cookie;
@ -661,7 +661,7 @@ gst_bin_get_state (GstElement * element, GstElementState * state,
* is still busy with its state change. */ * is still busy with its state change. */
GST_LOCK (bin); GST_LOCK (bin);
restart: restart:
ret = TRUE; ret = GST_STATE_SUCCESS;
children = bin->children; children = bin->children;
children_cookie = bin->children_cookie; children_cookie = bin->children_cookie;
while (children) { while (children) {
@ -670,13 +670,14 @@ restart:
gst_object_ref (GST_OBJECT_CAST (child)); gst_object_ref (GST_OBJECT_CAST (child));
GST_UNLOCK (bin); GST_UNLOCK (bin);
/* ret is false if some child is still performing the state change */ /* ret is ASYNC if some child is still performing the state change */
ret = gst_element_get_state (child, NULL, NULL, timeout); ret = gst_element_get_state (child, NULL, NULL, timeout);
gst_object_unref (GST_OBJECT_CAST (child)); gst_object_unref (GST_OBJECT_CAST (child));
if (!ret) { if (ret != GST_STATE_SUCCESS) {
/* some child is still busy, return FALSE */ /* some child is still busy or in error, we can report that
* right away. */
goto done; goto done;
} }
/* now grab the lock to iterate to the next child */ /* now grab the lock to iterate to the next child */
@ -692,9 +693,18 @@ restart:
done: done:
/* now we can take the state lock */ /* now we can take the state lock */
GST_STATE_LOCK (bin); GST_STATE_LOCK (bin);
if (ret) { switch (ret) {
/* no async children, we can commit the state */ case GST_STATE_SUCCESS:
gst_element_commit_state (element); /* we can commit the state */
gst_element_commit_state (element);
break;
case GST_STATE_FAILURE:
/* some element failed, abort the state change */
gst_element_abort_state (element);
break;
default:
/* other cases are just passed along */
break;
} }
/* and report the state if needed */ /* and report the state if needed */

View file

@ -66,7 +66,7 @@ static void gst_element_base_class_finalize (gpointer g_class);
static void gst_element_dispose (GObject * object); static void gst_element_dispose (GObject * object);
static GstElementStateReturn gst_element_change_state (GstElement * element); static GstElementStateReturn gst_element_change_state (GstElement * element);
static gboolean gst_element_get_state_func (GstElement * element, static GstElementStateReturn gst_element_get_state_func (GstElement * element,
GstElementState * state, GstElementState * pending, GTimeVal * timeout); GstElementState * state, GstElementState * pending, GTimeVal * timeout);
static void gst_element_set_manager_func (GstElement * element, static void gst_element_set_manager_func (GstElement * element,
GstPipeline * manager); GstPipeline * manager);
@ -1559,11 +1559,11 @@ gst_element_sync_state_with_parent (GstElement * element)
} }
/* MT safe */ /* MT safe */
static gboolean static GstElementStateReturn
gst_element_get_state_func (GstElement * element, gst_element_get_state_func (GstElement * element,
GstElementState * state, GstElementState * pending, GTimeVal * timeout) GstElementState * state, GstElementState * pending, GTimeVal * timeout)
{ {
gboolean ret = FALSE; GstElementStateReturn ret = GST_STATE_FAILURE;
GstElementState old_pending; GstElementState old_pending;
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
@ -1578,10 +1578,14 @@ gst_element_get_state_func (GstElement * element,
*state = GST_STATE (element); *state = GST_STATE (element);
if (pending) if (pending)
*pending = GST_STATE_PENDING (element); *pending = GST_STATE_PENDING (element);
ret = FALSE; ret = GST_STATE_ASYNC;
} else { } else {
/* could be success or failure, we could check here if the /* could be success or failure */
* state is equal to the old pending state */ if (old_pending == GST_STATE (element)) {
ret = GST_STATE_SUCCESS;
} else {
ret = GST_STATE_FAILURE;
}
} }
} }
/* if nothing is pending anymore we can return TRUE and /* if nothing is pending anymore we can return TRUE and
@ -1591,7 +1595,7 @@ gst_element_get_state_func (GstElement * element,
*state = GST_STATE (element); *state = GST_STATE (element);
if (pending) if (pending)
*pending = GST_STATE_VOID_PENDING; *pending = GST_STATE_VOID_PENDING;
ret = TRUE; ret = GST_STATE_SUCCESS;
} }
GST_STATE_UNLOCK (element); GST_STATE_UNLOCK (element);
@ -1605,23 +1609,32 @@ gst_element_get_state_func (GstElement * element,
* @pending: a pointer to #GstElementState to hold the pending state. * @pending: a pointer to #GstElementState to hold the pending state.
* Can be NULL. * Can be NULL.
* @timeout: a #GTimeVal to specify the timeout for an async * @timeout: a #GTimeVal to specify the timeout for an async
* state change. * state change or NULL for infinite timeout.
* *
* Gets the state of the element. * Gets the state of the element.
* *
* Returns: TRUE if the element has no more pending state, FALSE * For elements that performed an ASYNC state change, as reported by
* if the element is still performing a state change. * #gst_element_set_state(), this function will block up to the
* specified timeout value for the state change to complete.
* If the element completes the state change or goes into
* an error, this function returns immediatly with a return value of
* GST_STATE_SUCCESS or GST_STATE_FAILURE respectively.
*
* Returns: GST_STATE_SUCCESS if the element has no more pending state and
* the last state change succeeded, GST_STATE_ASYNC
* if the element is still performing a state change or
* GST_STATE_FAILURE if the last state change failed.
* *
* MT safe. * MT safe.
*/ */
gboolean GstElementStateReturn
gst_element_get_state (GstElement * element, gst_element_get_state (GstElement * element,
GstElementState * state, GstElementState * pending, GTimeVal * timeout) GstElementState * state, GstElementState * pending, GTimeVal * timeout)
{ {
GstElementClass *oclass; GstElementClass *oclass;
gboolean result = FALSE; GstElementStateReturn result = GST_STATE_FAILURE;
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
oclass = GST_ELEMENT_GET_CLASS (element); oclass = GST_ELEMENT_GET_CLASS (element);
@ -1652,14 +1665,14 @@ gst_element_abort_state (GstElement * element)
pending = GST_STATE_PENDING (element); pending = GST_STATE_PENDING (element);
if (pending != GST_STATE_VOID_PENDING) { if (pending != GST_STATE_VOID_PENDING && !GST_STATE_ERROR (element)) {
GstElementState old_state = GST_STATE (element); GstElementState old_state = GST_STATE (element);
GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
"aborting state from %s to %s", gst_element_state_get_name (old_state), "aborting state from %s to %s", gst_element_state_get_name (old_state),
gst_element_state_get_name (pending)); gst_element_state_get_name (pending));
GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING; GST_STATE_ERROR (element) = TRUE;
GST_STATE_BROADCAST (element); GST_STATE_BROADCAST (element);
} }
@ -1726,6 +1739,9 @@ gst_element_set_state (GstElement * element, GstElementState state)
/* get the element state lock */ /* get the element state lock */
GST_STATE_LOCK (element); GST_STATE_LOCK (element);
/* clear the error flag */
GST_STATE_ERROR (element) = FALSE;
/* start with the current state */ /* start with the current state */
current = GST_STATE (element); current = GST_STATE (element);
@ -1749,17 +1765,11 @@ gst_element_set_state (GstElement * element, GstElementState state)
/* set the pending state variable */ /* set the pending state variable */
GST_STATE_PENDING (element) = pending; GST_STATE_PENDING (element) = pending;
if (pending != state) { GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "%s: setting state from %s to %s",
"intermediate: setting state from %s to %s", (pending != state ? "intermediate" : "final"),
gst_element_state_get_name (current), gst_element_state_get_name (current),
gst_element_state_get_name (pending)); gst_element_state_get_name (pending));
} else {
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
"final: setting state from %s to %s",
gst_element_state_get_name (current),
gst_element_state_get_name (pending));
}
/* call the state change function so it can set the state */ /* call the state change function so it can set the state */
if (oclass->change_state) if (oclass->change_state)

View file

@ -66,6 +66,7 @@ struct _GstElementDetails
*/ */
#define GST_STATE(obj) (GST_ELEMENT(obj)->current_state) #define GST_STATE(obj) (GST_ELEMENT(obj)->current_state)
#define GST_STATE_PENDING(obj) (GST_ELEMENT(obj)->pending_state) #define GST_STATE_PENDING(obj) (GST_ELEMENT(obj)->pending_state)
#define GST_STATE_ERROR(obj) (GST_ELEMENT(obj)->state_error)
/* Note: using 8 bit shift mostly "just because", it leaves us enough room to grow <g> */ /* Note: using 8 bit shift mostly "just because", it leaves us enough room to grow <g> */
#define GST_STATE_TRANSITION(obj) ((GST_STATE(obj)<<8) | GST_STATE_PENDING(obj)) #define GST_STATE_TRANSITION(obj) ((GST_STATE(obj)<<8) | GST_STATE_PENDING(obj))
@ -173,32 +174,34 @@ struct _GstElement
/*< public > *//* with STATE_LOCK */ /*< public > *//* with STATE_LOCK */
/* element state */ /* element state */
GMutex *state_lock; GMutex *state_lock;
GCond *state_cond; GCond *state_cond;
guint8 current_state; guint8 current_state;
guint8 pending_state; guint8 pending_state;
gboolean state_error; /* flag is set when the element has an error in the last state
change. it is cleared when doing another state change. */
/*< public > *//* with LOCK */ /*< public > *//* with LOCK */
/* element manager */ /* element manager */
GstPipeline *manager; GstPipeline *manager;
GstBus *bus; GstBus *bus;
GstScheduler *scheduler; GstScheduler *scheduler;
/* private pointer for the scheduler */ /* private pointer for the scheduler */
gpointer sched_private; gpointer sched_private;
/* allocated clock */ /* allocated clock */
GstClock *clock; GstClock *clock;
GstClockTimeDiff base_time; /* NULL/READY: 0 - PAUSED: current time - PLAYING: difference to clock */ GstClockTimeDiff base_time; /* NULL/READY: 0 - PAUSED: current time - PLAYING: difference to clock */
/* element pads, these lists can only be iterated while holding /* element pads, these lists can only be iterated while holding
* the LOCK or checking the cookie after each LOCK. */ * the LOCK or checking the cookie after each LOCK. */
guint16 numpads; guint16 numpads;
GList *pads; GList *pads;
guint16 numsrcpads; guint16 numsrcpads;
GList *srcpads; GList *srcpads;
guint16 numsinkpads; guint16 numsinkpads;
GList *sinkpads; GList *sinkpads;
guint32 pads_cookie; guint32 pads_cookie;
/*< private > */ /*< private > */
gpointer _gst_reserved[GST_PADDING]; gpointer _gst_reserved[GST_PADDING];
@ -236,9 +239,9 @@ struct _GstElementClass
void (*release_pad) (GstElement * element, GstPad * pad); void (*release_pad) (GstElement * element, GstPad * pad);
/* state changes */ /* state changes */
gboolean (*get_state) (GstElement * element, GstElementState * state, GstElementStateReturn (*get_state) (GstElement * element, GstElementState * state,
GstElementState * pending, GTimeVal * timeout); GstElementState * pending, GTimeVal * timeout);
GstElementStateReturn (*change_state) (GstElement * element); GstElementStateReturn (*change_state) (GstElement * element);
/* manager */ /* manager */
void (*set_manager) (GstElement * element, GstPipeline * pipeline); void (*set_manager) (GstElement * element, GstPipeline * pipeline);
@ -353,18 +356,20 @@ void gst_element_message_full (GstElement * element, GstMessageType type,
const gchar * function, gint line); const gchar * function, gint line);
/* state management */ /* state management */
gboolean gst_element_is_locked_state (GstElement * element); gboolean gst_element_is_locked_state (GstElement * element);
gboolean gst_element_set_locked_state (GstElement * element, gboolean gst_element_set_locked_state (GstElement * element,
gboolean locked_state); gboolean locked_state);
gboolean gst_element_sync_state_with_parent (GstElement * element); gboolean gst_element_sync_state_with_parent (GstElement * element);
gboolean gst_element_get_state (GstElement * element, GstElementState * state, GstElementStateReturn gst_element_get_state (GstElement * element,
GstElementState * pending, GTimeVal * timeout); GstElementState * state,
GstElementStateReturn gst_element_set_state (GstElement * element, GstElementState * pending,
GstElementState state); GTimeVal * timeout);
GstElementStateReturn gst_element_set_state (GstElement * element,
GstElementState state);
void gst_element_abort_state (GstElement * element); void gst_element_abort_state (GstElement * element);
void gst_element_commit_state (GstElement * element); void gst_element_commit_state (GstElement * element);
/* factory management */ /* factory management */
GstElementFactory *gst_element_get_factory (GstElement * element); GstElementFactory *gst_element_get_factory (GstElement * element);