Commit d14c4c4a authored by Wim Taymans's avatar Wim Taymans

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.
parent d6626399
2007-03-19 Wim Taymans <wim@fluendo.com>
* 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.
2007-03-19 Wim Taymans <wim@fluendo.com>
* docs/gst/gstreamer-sections.txt:
......
......@@ -419,6 +419,7 @@ GST_STATE_GET_NEXT
GST_STATE_NEXT
GST_STATE_PENDING
GST_STATE_RETURN
GST_STATE_TARGET
GST_STATE_TRANSITION
GST_STATE_TRANSITION_CURRENT
GST_STATE_TRANSITION_NEXT
......@@ -500,6 +501,7 @@ gst_element_lost_state
gst_element_state_get_name
gst_element_state_change_return_get_name
gst_element_sync_state_with_parent
gst_element_change_state
<SUBSECTION element-tags>
gst_element_found_tags
......
This diff is collapsed.
......@@ -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");
......
......@@ -119,6 +119,16 @@ typedef enum {
*/
#define GST_STATE_PENDING(elem) (GST_ELEMENT_CAST(elem)->pending_state)
/**
* GST_STATE_TARGET:
* @elem: a #GstElement to return the target state for.
*
* This macro returns the target #GstState of the element.
*
* Since: 0.10.13
*/
#define GST_STATE_TARGET(elem) (GST_ELEMENT_CAST(elem)->abidata.ABI.target_state)
/**
* GST_STATE_RETURN:
* @elem: a #GstElement to return the last state result for.
......@@ -427,7 +437,14 @@ struct _GstElement
guint32 pads_cookie;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
union {
struct {
/* state set by application */
GstState target_state;
} ABI;
/* adding + 0 to mark ABI change to be undone later */
gpointer _gst_reserved[GST_PADDING + 0];
} abidata;
};
/**
......@@ -626,6 +643,8 @@ GstStateChangeReturn gst_element_get_state (GstElement * element,
GstStateChangeReturn gst_element_set_state (GstElement *element, GstState state);
void gst_element_abort_state (GstElement * element);
GstStateChangeReturn gst_element_change_state (GstElement * element,
GstStateChange transition);
GstStateChangeReturn gst_element_continue_state (GstElement * element,
GstStateChangeReturn ret);
void gst_element_lost_state (GstElement * element);
......
......@@ -120,6 +120,8 @@ struct _GstPipelinePrivate
{
/* with LOCK */
gboolean auto_flush_bus;
GstClockTime new_stream_time;
};
......@@ -133,13 +135,12 @@ static void gst_pipeline_set_property (GObject * object, guint prop_id,
static void gst_pipeline_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_pipeline_send_event (GstElement * element,
GstEvent * event);
static GstClock *gst_pipeline_provide_clock_func (GstElement * element);
static GstStateChangeReturn gst_pipeline_change_state (GstElement * element,
GstStateChange transition);
static void gst_pipeline_handle_message (GstBin * bin, GstMessage * message);
static GstBinClass *parent_class = NULL;
/* static guint gst_pipeline_signals[LAST_SIGNAL] = { 0 }; */
......@@ -185,6 +186,7 @@ gst_pipeline_class_init (gpointer g_class, gpointer class_data)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
GstBinClass *gstbin_class = GST_BIN_CLASS (g_class);
GstPipelineClass *klass = GST_PIPELINE_CLASS (g_class);
parent_class = g_type_class_peek_parent (klass);
......@@ -226,11 +228,13 @@ gst_pipeline_class_init (gpointer g_class, gpointer class_data)
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_pipeline_dispose);
gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_pipeline_send_event);
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_pipeline_change_state);
gstelement_class->provide_clock =
GST_DEBUG_FUNCPTR (gst_pipeline_provide_clock_func);
gstbin_class->handle_message =
GST_DEBUG_FUNCPTR (gst_pipeline_handle_message);
}
static void
......@@ -311,90 +315,19 @@ gst_pipeline_get_property (GObject * object, guint prop_id,
}
}
/* default pipeline seeking code:
*
* If the pipeline is PLAYING and a flushing seek is done, set
* the pipeline to PAUSED before doing the seek.
*
* A flushing seek also resets the stream time to 0 so that when
* we go back to PLAYING after the seek, the base_time is recalculated
* and redistributed to the elements.
*/
static gboolean
do_pipeline_seek (GstElement * element, GstEvent * event)
{
gdouble rate;
GstSeekFlags flags;
gboolean flush;
gboolean was_playing = FALSE;
gboolean res;
/* we are only interested in the FLUSH flag of the seek event. */
gst_event_parse_seek (event, &rate, NULL, &flags, NULL, NULL, NULL, NULL);
flush = flags & GST_SEEK_FLAG_FLUSH;
/* if flushing seek, get the current state */
if (flush) {
GstState state;
/* need to call _get_state() since a bin state is only updated
* with this call. */
gst_element_get_state (element, &state, NULL, 0);
was_playing = (state == GST_STATE_PLAYING);
if (was_playing) {
/* and PAUSE when the pipeline was PLAYING, we don't need
* to wait for the state change to complete since we are going
* to flush out any preroll sample anyway. */
gst_element_set_state (element, GST_STATE_PAUSED);
}
}
/* let parent class implement the seek behaviour */
res = GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
/* if flushing seek restore previous state */
if (flush) {
gboolean need_reset;
GST_OBJECT_LOCK (element);
need_reset = GST_PIPELINE (element)->stream_time != GST_CLOCK_TIME_NONE;
GST_OBJECT_UNLOCK (element);
/* need to reset the stream time to 0 after a successfull flushing seek,
* unless the user explicitly disabled this behavior by setting stream
* time to NONE */
if (need_reset && res)
gst_pipeline_set_new_stream_time (GST_PIPELINE (element), 0);
if (was_playing)
/* and continue playing, this might return ASYNC in which case the
* application can wait for the PREROLL to complete after the seek.
*/
gst_element_set_state (element, GST_STATE_PLAYING);
}
return res;
}
static gboolean
gst_pipeline_send_event (GstElement * element, GstEvent * event)
/* set the stream time to 0 */
static void
reset_stream_time (GstPipeline * pipeline)
{
gboolean res;
GstEventType event_type = GST_EVENT_TYPE (event);
switch (event_type) {
case GST_EVENT_SEEK:
/* do the default seek handling */
res = do_pipeline_seek (element, event);
break;
default:
/* else parent implements the defaults */
res = GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
break;
GST_OBJECT_LOCK (pipeline);
if (pipeline->stream_time != GST_CLOCK_TIME_NONE) {
GST_DEBUG_OBJECT (pipeline, "reset stream_time to 0");
pipeline->stream_time = 0;
pipeline->priv->new_stream_time = TRUE;
} else {
GST_DEBUG_OBJECT (pipeline, "application asked to not reset stream_time");
}
return res;
GST_OBJECT_UNLOCK (pipeline);
}
/**
......@@ -433,8 +366,11 @@ gst_pipeline_change_state (GstElement * element, GstStateChange transition)
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
{
GstClockTime new_base_time;
GstQuery *query;
GstClockTime min_latency, max_latency;
GstClockTime start_time, stream_time, delay;
gboolean new_clock;
gboolean new_clock, update;
gboolean res;
GST_DEBUG_OBJECT (element, "selecting clock and base_time");
......@@ -452,6 +388,8 @@ gst_pipeline_change_state (GstElement * element, GstStateChange transition)
GST_OBJECT_LOCK (element);
new_clock = element->clock != clock;
stream_time = pipeline->stream_time;
update = pipeline->priv->new_stream_time;
pipeline->priv->new_stream_time = FALSE;
delay = pipeline->delay;
GST_OBJECT_UNLOCK (element);
......@@ -468,25 +406,68 @@ gst_pipeline_change_state (GstElement * element, GstStateChange transition)
gst_message_new_new_clock (GST_OBJECT_CAST (element), clock));
}
if (stream_time != GST_CLOCK_TIME_NONE
&& start_time != GST_CLOCK_TIME_NONE) {
new_base_time = start_time - stream_time + delay;
GST_DEBUG_OBJECT (element,
"stream_time=%" GST_TIME_FORMAT ", now=%" GST_TIME_FORMAT
", base_time %" GST_TIME_FORMAT,
GST_TIME_ARGS (stream_time), GST_TIME_ARGS (start_time),
GST_TIME_ARGS (new_base_time));
} else
new_base_time = GST_CLOCK_TIME_NONE;
if (clock)
gst_object_unref (clock);
if (new_base_time != GST_CLOCK_TIME_NONE)
gst_element_set_base_time (element, new_base_time);
else
/* stream time changed, either with a PAUSED or a flush, we need to update
* the base time */
if (update) {
GST_DEBUG_OBJECT (pipeline, "stream_time changed, updating base time");
if (stream_time != GST_CLOCK_TIME_NONE
&& start_time != GST_CLOCK_TIME_NONE) {
new_base_time = start_time - stream_time + delay;
GST_DEBUG_OBJECT (element,
"stream_time=%" GST_TIME_FORMAT ", now=%" GST_TIME_FORMAT
", base_time %" GST_TIME_FORMAT,
GST_TIME_ARGS (stream_time), GST_TIME_ARGS (start_time),
GST_TIME_ARGS (new_base_time));
} else
new_base_time = GST_CLOCK_TIME_NONE;
if (new_base_time != GST_CLOCK_TIME_NONE)
gst_element_set_base_time (element, new_base_time);
else
GST_DEBUG_OBJECT (pipeline,
"NOT adjusting base_time because stream_time is NONE");
} else {
GST_DEBUG_OBJECT (pipeline,
"NOT adjusting base time because stream time is NONE");
"NOT adjusting base_time because we selected one before");
}
/* determine latency in this pipeline */
GST_DEBUG_OBJECT (element, "querying pipeline latency");
query = gst_query_new_latency ();
if (gst_element_query (element, query)) {
gboolean live;
gst_query_parse_latency (query, &live, &min_latency, &max_latency);
GST_DEBUG_OBJECT (element,
"configuring min latency %" GST_TIME_FORMAT ", max latency %"
GST_TIME_FORMAT ", live %d", GST_TIME_ARGS (min_latency),
GST_TIME_ARGS (max_latency), live);
/* configure latency on elements */
res =
gst_element_send_event (element,
gst_event_new_latency (min_latency));
if (res) {
GST_INFO_OBJECT (element, "configured latency of %" GST_TIME_FORMAT,
GST_TIME_ARGS (min_latency));
} else {
GST_WARNING_OBJECT (element,
"failed to configure latency of %" GST_TIME_FORMAT,
GST_TIME_ARGS (min_latency));
GST_ELEMENT_WARNING (element, CORE, CLOCK, (NULL),
("Failed to configure latency of %" GST_TIME_FORMAT,
GST_TIME_ARGS (min_latency)));
}
} else {
/* this is not a real problem, we just don't configure any latency. */
GST_WARNING_OBJECT (element, "failed to query pipeline latency");
}
gst_query_unref (query);
break;
}
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
......@@ -503,17 +484,7 @@ gst_pipeline_change_state (GstElement * element, GstStateChange transition)
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
{
gboolean need_reset;
/* only reset the stream_time when the application did not
* specify a stream_time explicitly */
GST_OBJECT_LOCK (element);
need_reset = pipeline->stream_time != GST_CLOCK_TIME_NONE;
GST_OBJECT_UNLOCK (element);
if (need_reset)
gst_pipeline_set_new_stream_time (pipeline, 0);
reset_stream_time (pipeline);
break;
}
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
......@@ -532,8 +503,11 @@ gst_pipeline_change_state (GstElement * element, GstStateChange transition)
GST_OBJECT_LOCK (element);
/* store the current stream time */
if (pipeline->stream_time != GST_CLOCK_TIME_NONE)
if (pipeline->stream_time != GST_CLOCK_TIME_NONE) {
pipeline->stream_time = now - element->base_time;
pipeline->priv->new_stream_time = TRUE;
}
GST_DEBUG_OBJECT (element,
"stream_time=%" GST_TIME_FORMAT ", now=%" GST_TIME_FORMAT
", base_time %" GST_TIME_FORMAT,
......@@ -574,6 +548,32 @@ invalid_clock:
}
}
static void
gst_pipeline_handle_message (GstBin * bin, GstMessage * message)
{
GstPipeline *pipeline = GST_PIPELINE_CAST (bin);
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_ASYNC_START:
{
gboolean new_base_time;
gst_message_parse_async_start (message, &new_base_time);
/* reset our stream time if we need to distribute a new base_time to the
* children. */
if (new_base_time)
reset_stream_time (pipeline);
break;
}
default:
break;
}
GST_BIN_CLASS (parent_class)->handle_message (bin, message);