summaryrefslogtreecommitdiff
path: root/gst/gstelement.c
diff options
context:
space:
mode:
authorWim Taymans <wim.taymans@gmail.com>2007-03-19 10:47:56 +0000
committerWim Taymans <wim.taymans@gmail.com>2007-03-19 10:47:56 +0000
commitd14c4c4a678f2874d7c59e2be6d6887a324ae5b1 (patch)
tree813ea84b5c75b3f14874d2b89c4289516e200278 /gst/gstelement.c
parentd66263996dcddf057c952ab7a887aa8b33a6a9b3 (diff)
docs/gst/gstreamer-sections.txt: Add new element field and method.
Original commit message from CVS: * docs/gst/gstreamer-sections.txt: Add new element field and method. * gst/gstbin.c: (gst_bin_class_init), (gst_bin_init), (bin_remove_messages), (gst_bin_add_func), (gst_bin_remove_func), (gst_bin_recalc_state), (gst_bin_get_state_func), (gst_bin_element_set_state), (gst_bin_change_state_func), (gst_bin_continue_func), (bin_bus_handler), (bin_push_state_continue), (bin_handle_async_start), (bin_handle_async_done), (gst_bin_handle_message_func): Make async state changes a bit smarter by using new ASYNC_START and ASYNC_DONE messages. This reduces the number of times we run the state recalculation thread. Don't change state of element with a pending ASYNC_START message. Deprecate STATE_DIRTY messages. * gst/gstelement.c: (gst_element_init), (gst_element_send_event), (gst_element_get_state_func), (gst_element_continue_state), (gst_element_lost_state), (gst_element_set_state_func), (gst_element_change_state): * gst/gstelement.h: Keep the state that was last set by the app in a new element field. Don't allow state changes when handling an element event. Post ASYNC_START and ASYNC_DONE messages. Change lost_state so that we go to PAUSED and wait for the parent to set us to PLAYING again (so latency calculation can be performed) Export gst_element_change_state() method so that subclasses can use it. API: gst_element_change_state() API: GST_STATE_TARGET * gst/gstpipeline.c: (gst_pipeline_class_init), (reset_stream_time), (gst_pipeline_change_state), (gst_pipeline_handle_message), (gst_pipeline_set_new_stream_time): Using the new ASYNC_START message we can reset the base_time when needed. This can then be used to implement base_time redistribution in flushing seeks so that we can remove the explicit seek handling. Perform latency query and configuration when going to PLAYING. * libs/gst/base/gstbasesink.c: (gst_base_sink_commit_state), (gst_base_sink_query), (gst_base_sink_change_state): Post new ASYNC_START/ASYNC_DONE messages. * tests/check/generic/sinks.c: (GST_START_TEST): Fix test because the bin will not set the async element to PLAYING right away. * tests/check/gst/gstbin.c: (pop_async_done), (GST_START_TEST): Make the message check a little stronger. Handle ASYNC messages. * tests/check/pipelines/cleanup.c: (GST_START_TEST): * tests/check/pipelines/simple-launch-lines.c: (GST_START_TEST): Expect ASYNC_DONE messages.
Diffstat (limited to 'gst/gstelement.c')
-rw-r--r--gst/gstelement.c93
1 files changed, 66 insertions, 27 deletions
diff --git a/gst/gstelement.c b/gst/gstelement.c
index be458ca5b..30880f85d 100644
--- a/gst/gstelement.c
+++ b/gst/gstelement.c
@@ -82,6 +82,7 @@
#include <gobject/gvaluecollector.h>
#include "gstelement.h"
+#include "gstenumtypes.h"
#include "gstbus.h"
#include "gstmarshal.h"
#include "gsterror.h"
@@ -118,8 +119,6 @@ static void gst_element_base_class_finalize (gpointer g_class);
static void gst_element_dispose (GObject * object);
static void gst_element_finalize (GObject * object);
-static GstStateChangeReturn gst_element_change_state (GstElement * element,
- GstStateChange transition);
static GstStateChangeReturn gst_element_change_state_func (GstElement * element,
GstStateChange transition);
static GstStateChangeReturn gst_element_get_state_func (GstElement * element,
@@ -254,6 +253,7 @@ static void
gst_element_init (GstElement * element)
{
GST_STATE (element) = GST_STATE_NULL;
+ GST_STATE_TARGET (element) = GST_STATE_NULL;
GST_STATE_NEXT (element) = GST_STATE_VOID_PENDING;
GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
GST_STATE_RETURN (element) = GST_STATE_CHANGE_SUCCESS;
@@ -1295,6 +1295,7 @@ gst_element_send_event (GstElement * element, GstEvent * event)
oclass = GST_ELEMENT_GET_CLASS (element);
+ GST_STATE_LOCK (element);
if (oclass->send_event) {
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "send %s event on element %s",
GST_EVENT_TYPE_NAME (event), GST_ELEMENT_NAME (element));
@@ -1302,6 +1303,8 @@ gst_element_send_event (GstElement * element, GstEvent * event)
} else {
result = gst_element_default_send_event (element, event);
}
+ GST_STATE_UNLOCK (element);
+
return result;
}
@@ -1762,6 +1765,9 @@ gst_element_get_state_func (GstElement * element,
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "RETURN is %s",
gst_element_state_change_return_get_name (ret));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "RETURN is %s",
+ gst_element_state_change_return_get_name (ret));
+
/* we got an error, report immediatly */
if (ret == GST_STATE_CHANGE_FAILURE)
goto done;
@@ -1984,14 +1990,14 @@ nothing_aborted:
GstStateChangeReturn
gst_element_continue_state (GstElement * element, GstStateChangeReturn ret)
{
- GstState pending;
- GstState old_ret, old_state, old_next;
- GstState current, next;
+ GstStateChangeReturn old_ret;
+ GstState old_state, old_next;
+ GstState current, next, pending;
GstMessage *message;
GstStateChange transition;
GST_OBJECT_LOCK (element);
- old_ret = (GstState) GST_STATE_RETURN (element);
+ old_ret = GST_STATE_RETURN (element);
GST_STATE_RETURN (element) = ret;
pending = GST_STATE_PENDING (element);
@@ -2047,7 +2053,8 @@ complete:
GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
GST_STATE_NEXT (element) = GST_STATE_VOID_PENDING;
- GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "completed state change");
+ GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
+ "completed state change to %s", gst_element_state_get_name (pending));
GST_OBJECT_UNLOCK (element);
/* don't post silly messages with the same state. This can happen
@@ -2076,10 +2083,16 @@ complete:
* element is copied to the pending state so that any call to
* gst_element_get_state() will return %GST_STATE_CHANGE_ASYNC.
*
+ * An ASYNC_START message is posted with an indication to distribute a new
+ * base_time to the element.
+ * If the element was PLAYING, it will go to PAUSED. The element
+ * will be restored to its PLAYING state by the parent pipeline when it
+ * prerolls again.
+ *
* This is mostly used for elements that lost their preroll buffer
- * in the %GST_STATE_PAUSED state after a flush, they become %GST_STATE_PAUSED
- * again if a new preroll buffer is queued.
- * This function can only be called when the element is currently
+ * in the %GST_STATE_PAUSED or %GST_STATE_PLAYING state after a flush,
+ * they will go to their pending state again when a new preroll buffer is
+ * queued. This function can only be called when the element is currently
* not in error or an async state change.
*
* This function is used internally and should normally not be called from
@@ -2090,7 +2103,7 @@ complete:
void
gst_element_lost_state (GstElement * element)
{
- GstState current_state;
+ GstState old_state, new_state;
GstMessage *message;
g_return_if_fail (GST_IS_ELEMENT (element));
@@ -2100,22 +2113,31 @@ gst_element_lost_state (GstElement * element)
GST_STATE_RETURN (element) == GST_STATE_CHANGE_FAILURE)
goto nothing_lost;
- current_state = GST_STATE (element);
+ old_state = GST_STATE (element);
+
+ /* when we were PLAYING, the new state is PAUSED. We will also not
+ * automatically go to PLAYING but let the parent bin(s) set us to PLAYING
+ * when we preroll. */
+ if (old_state > GST_STATE_PAUSED)
+ new_state = GST_STATE_PAUSED;
+ else
+ new_state = old_state;
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
- "lost state of %s", gst_element_state_get_name (current_state));
+ "lost state of %s to %s", gst_element_state_get_name (old_state),
+ gst_element_state_get_name (new_state));
- GST_STATE_NEXT (element) = current_state;
- GST_STATE_PENDING (element) = current_state;
+ GST_STATE (element) = new_state;
+ GST_STATE_NEXT (element) = new_state;
+ GST_STATE_PENDING (element) = new_state;
GST_STATE_RETURN (element) = GST_STATE_CHANGE_ASYNC;
GST_OBJECT_UNLOCK (element);
message = gst_message_new_state_changed (GST_OBJECT_CAST (element),
- current_state, current_state, current_state);
+ new_state, new_state, new_state);
gst_element_post_message (element, message);
- /* and mark us dirty */
- message = gst_message_new_state_dirty (GST_OBJECT_CAST (element));
+ message = gst_message_new_async_start (GST_OBJECT_CAST (element), TRUE);
gst_element_post_message (element, message);
return;
@@ -2200,7 +2222,9 @@ gst_element_set_state_func (GstElement * element, GstState state)
/* increment state cookie so that we can track each state change */
element->state_cookie++;
- /* this is the (new) state we should go to */
+ /* this is the (new) state we should go to. TARGET is the last state we set on
+ * the element. */
+ GST_STATE_TARGET (element) = state;
GST_STATE_PENDING (element) = state;
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
@@ -2271,8 +2295,19 @@ was_busy:
}
}
-/* with STATE_LOCK */
-static GstStateChangeReturn
+/**
+ * gst_element_change_state:
+ * @element: a #GstElement
+ * @transition: the requested transition
+ *
+ * Perform @transition on @element.
+ *
+ * This function must be called with STATE_LOCK held and is mainly used
+ * internally.
+ *
+ * Returns: the #GstStateChangeReturn of the state transition.
+ */
+GstStateChangeReturn
gst_element_change_state (GstElement * element, GstStateChange transition)
{
GstElementClass *oclass;
@@ -2300,22 +2335,26 @@ gst_element_change_state (GstElement * element, GstStateChange transition)
gst_element_abort_state (element);
break;
case GST_STATE_CHANGE_ASYNC:
+ {
+ GstState target;
+
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
"element will change state ASYNC");
- /* if we go upwards, we give the app a change to wait for
- * completion */
- if (current < next)
+ target = GST_STATE_TARGET (element);
+
+ if (target > GST_STATE_READY)
goto async;
/* else we just continue the state change downwards */
GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
- "forcing commit state %s < %s",
- gst_element_state_get_name (current),
- gst_element_state_get_name (next));
+ "forcing commit state %s <= %s",
+ gst_element_state_get_name (target),
+ gst_element_state_get_name (GST_STATE_READY));
ret = gst_element_continue_state (element, GST_STATE_CHANGE_SUCCESS);
break;
+ }
case GST_STATE_CHANGE_SUCCESS:
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
"element changed state SUCCESS");