message: move the new_base_time flag to async_done

Move the flag to indicate that a new_base_time should be distributed to the
pipeline, from the async_start to the async_done message. This would allow us to
decide when to reset the pipeline time based on other reasons than the
FLUSH_START event.

The main goal eventually is to make the FLUSH events not reset time at all but
reset the time based on the first buffer or segment that prerolls the pipeline
again.
This commit is contained in:
Wim Taymans 2011-06-08 13:40:32 +02:00
parent 054a770063
commit 3cb8b33935
9 changed files with 59 additions and 66 deletions

View file

@ -227,8 +227,8 @@ static void gst_bin_state_changed (GstElement * element, GstState oldstate,
static GstStateChangeReturn gst_bin_get_state_func (GstElement * element,
GstState * state, GstState * pending, GstClockTime timeout);
static void bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret,
gboolean flag_pending);
static void bin_handle_async_start (GstBin * bin, gboolean new_base_time);
gboolean flag_pending, gboolean new_base_time);
static void bin_handle_async_start (GstBin * bin);
static void bin_push_state_continue (BinContinueData * data);
static void bin_do_eos (GstBin * bin);
@ -1125,13 +1125,12 @@ gst_bin_add_func (GstBin * bin, GstElement * element)
{
/* create message to track this aync element when it posts an async-done
* message */
async_message =
gst_message_new_async_start (GST_OBJECT_CAST (element), FALSE);
async_message = gst_message_new_async_start (GST_OBJECT_CAST (element));
break;
}
case GST_STATE_CHANGE_NO_PREROLL:
/* ignore all async elements we might have and commit our state */
bin_handle_async_done (bin, ret, FALSE);
bin_handle_async_done (bin, ret, FALSE, FALSE);
break;
case GST_STATE_CHANGE_FAILURE:
break;
@ -1425,7 +1424,7 @@ gst_bin_remove_func (GstBin * bin, GstElement * element)
else
ret = GST_STATE_CHANGE_SUCCESS;
bin_handle_async_done (bin, ret, FALSE);
bin_handle_async_done (bin, ret, FALSE, FALSE);
} else {
GST_DEBUG_OBJECT (bin,
"recalc state preroll: %d, other async: %d, this async %d",
@ -2628,7 +2627,7 @@ done:
bin_remove_messages (bin, NULL, GST_MESSAGE_ASYNC_DONE);
GST_DEBUG_OBJECT (bin, "async elements commited");
bin_handle_async_done (bin, GST_STATE_CHANGE_SUCCESS, FALSE);
bin_handle_async_done (bin, GST_STATE_CHANGE_SUCCESS, FALSE, FALSE);
}
state_end:
@ -2803,7 +2802,7 @@ bin_push_state_continue (BinContinueData * data)
* This function is called with the OBJECT lock.
*/
static void
bin_handle_async_start (GstBin * bin, gboolean new_base_time)
bin_handle_async_start (GstBin * bin)
{
GstState old_state, new_state;
gboolean toplevel;
@ -2819,8 +2818,7 @@ bin_handle_async_start (GstBin * bin, gboolean new_base_time)
* are busy with a state change or when we are NO_PREROLL. */
if (!toplevel)
/* non toplevel bin, prepare async-start for the parent */
amessage =
gst_message_new_async_start (GST_OBJECT_CAST (bin), new_base_time);
amessage = gst_message_new_async_start (GST_OBJECT_CAST (bin));
if (bin->polling || GST_STATE_PENDING (bin) != GST_STATE_VOID_PENDING)
goto was_busy;
@ -2887,7 +2885,7 @@ was_no_preroll:
*/
static void
bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret,
gboolean flag_pending)
gboolean flag_pending, gboolean new_base_time)
{
GstState current, pending, target;
GstStateChangeReturn old_ret;
@ -2915,7 +2913,7 @@ bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret,
target = GST_STATE_TARGET (bin);
pending = GST_STATE_PENDING (bin) = target;
amessage = gst_message_new_async_done (GST_OBJECT_CAST (bin));
amessage = gst_message_new_async_done (GST_OBJECT_CAST (bin), new_base_time);
old_state = GST_STATE (bin);
/* this is the state we should go to next */
@ -3305,14 +3303,11 @@ gst_bin_handle_message_func (GstBin * bin, GstMessage * message)
}
case GST_MESSAGE_ASYNC_START:
{
gboolean new_base_time;
GstState target;
GST_DEBUG_OBJECT (bin, "ASYNC_START message %p, %s", message,
src ? GST_OBJECT_NAME (src) : "(NULL)");
gst_message_parse_async_start (message, &new_base_time);
GST_OBJECT_LOCK (bin);
bin_do_message_forward (bin, message);
@ -3323,7 +3318,7 @@ gst_bin_handle_message_func (GstBin * bin, GstMessage * message)
/* takes ownership of the message */
bin_replace_message (bin, message, GST_MESSAGE_ASYNC_START);
bin_handle_async_start (bin, new_base_time);
bin_handle_async_start (bin);
GST_OBJECT_UNLOCK (bin);
break;
@ -3338,11 +3333,14 @@ gst_bin_handle_message_func (GstBin * bin, GstMessage * message)
}
case GST_MESSAGE_ASYNC_DONE:
{
gboolean new_base_time;
GstState target;
GST_DEBUG_OBJECT (bin, "ASYNC_DONE message %p, %s", message,
src ? GST_OBJECT_NAME (src) : "(NULL)");
gst_message_parse_async_done (message, &new_base_time);
GST_OBJECT_LOCK (bin);
bin_do_message_forward (bin, message);
@ -3363,7 +3361,8 @@ gst_bin_handle_message_func (GstBin * bin, GstMessage * message)
* need to set the pending_done flag so that at the end of the state
* change we can see if we need to verify pending async elements, hence
* the TRUE argument here. */
bin_handle_async_done (bin, GST_STATE_CHANGE_SUCCESS, TRUE);
bin_handle_async_done (bin, GST_STATE_CHANGE_SUCCESS, TRUE,
new_base_time);
} else {
GST_DEBUG_OBJECT (bin, "there are more async elements pending");
}

View file

@ -2335,17 +2335,14 @@ complete:
/**
* gst_element_lost_state:
* @element: a #GstElement the state is lost of
* @new_base_time: if a new base time should be distributed
*
* Brings the element to the lost state. The current state of the
* 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 indication to distribute a new
* base_time to the element when @new_base_time is %TRUE.
* 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.
* An ASYNC_START message is posted. 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 or %GST_STATE_PLAYING state after a flush,
@ -2357,7 +2354,7 @@ complete:
* plugins or applications.
*/
void
gst_element_lost_state (GstElement * element, gboolean new_base_time)
gst_element_lost_state (GstElement * element)
{
GstState old_state, new_state;
GstMessage *message;
@ -2389,14 +2386,11 @@ gst_element_lost_state (GstElement * element, gboolean new_base_time)
GST_STATE_NEXT (element) = new_state;
GST_STATE_PENDING (element) = new_state;
GST_STATE_RETURN (element) = GST_STATE_CHANGE_ASYNC;
if (new_base_time)
GST_ELEMENT_START_TIME (element) = 0;
GST_OBJECT_UNLOCK (element);
_priv_gst_element_state_changed (element, new_state, new_state, new_state);
message =
gst_message_new_async_start (GST_OBJECT_CAST (element), new_base_time);
message = gst_message_new_async_start (GST_OBJECT_CAST (element));
gst_element_post_message (element, message);
return;
@ -2410,7 +2404,7 @@ only_async_start:
{
GST_OBJECT_UNLOCK (element);
message = gst_message_new_async_start (GST_OBJECT_CAST (element), TRUE);
message = gst_message_new_async_start (GST_OBJECT_CAST (element));
gst_element_post_message (element, message);
return;
}

View file

@ -802,7 +802,7 @@ 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, gboolean new_base_time);
void gst_element_lost_state (GstElement * element);
/* factory management */
GstElementFactory* gst_element_get_factory (GstElement *element);

View file

@ -870,27 +870,19 @@ gst_message_new_duration (GstObject * src, GstFormat format, gint64 duration)
/**
* gst_message_new_async_start:
* @src: (transfer none): The object originating the message.
* @new_base_time: if a new base_time should be set on the element
*
* This message is posted by elements when they start an ASYNC state change.
* @new_base_time is set to TRUE when the element lost its state when it was
* PLAYING.
* This message is posted by elements when they start an ASYNC state change.
*
* Returns: (transfer full): The new async_start message.
*
* MT safe.
*
* Since: 0.10.13
*/
GstMessage *
gst_message_new_async_start (GstObject * src, gboolean new_base_time)
gst_message_new_async_start (GstObject * src)
{
GstMessage *message;
GstStructure *structure;
structure = gst_structure_id_new (GST_QUARK (MESSAGE_ASYNC_START),
GST_QUARK (NEW_BASE_TIME), G_TYPE_BOOLEAN, new_base_time, NULL);
message = gst_message_new_custom (GST_MESSAGE_ASYNC_START, src, structure);
message = gst_message_new_custom (GST_MESSAGE_ASYNC_START, src, NULL);
return message;
}
@ -898,21 +890,25 @@ gst_message_new_async_start (GstObject * src, gboolean new_base_time)
/**
* gst_message_new_async_done:
* @src: (transfer none): The object originating the message.
* @new_base_time: if a new base_time should be set on the element
*
* The message is posted when elements completed an ASYNC state change.
* @new_base_time is set to TRUE when the element requests a new base_time
* before going to PLAYING.
*
* Returns: (transfer full): The new async_done message.
*
* MT safe.
*
* Since: 0.10.13
*/
GstMessage *
gst_message_new_async_done (GstObject * src)
gst_message_new_async_done (GstObject * src, gboolean new_base_time)
{
GstMessage *message;
GstStructure *structure;
message = gst_message_new_custom (GST_MESSAGE_ASYNC_DONE, src, NULL);
structure = gst_structure_id_new (GST_QUARK (MESSAGE_ASYNC_DONE),
GST_QUARK (NEW_BASE_TIME), G_TYPE_BOOLEAN, new_base_time, NULL);
message = gst_message_new_custom (GST_MESSAGE_ASYNC_DONE, src, structure);
return message;
}
@ -1607,23 +1603,21 @@ gst_message_parse_duration (GstMessage * message, GstFormat * format,
}
/**
* gst_message_parse_async_start:
* gst_message_parse_async_done:
* @message: A valid #GstMessage of type GST_MESSAGE_ASYNC_DONE.
* @new_base_time: (out): Result location for the new_base_time or NULL
*
* Extract the new_base_time from the async_start message.
* Extract the new_base_time from the async_done message.
*
* MT safe.
*
* Since: 0.10.13
*/
void
gst_message_parse_async_start (GstMessage * message, gboolean * new_base_time)
gst_message_parse_async_done (GstMessage * message, gboolean * new_base_time)
{
GstStructure *structure;
g_return_if_fail (GST_IS_MESSAGE (message));
g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ASYNC_START);
g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ASYNC_DONE);
structure = GST_MESSAGE_STRUCTURE (message);
if (new_base_time)

View file

@ -493,11 +493,11 @@ void gst_message_parse_duration (GstMessage *message, GstFormat
GstMessage * gst_message_new_latency (GstObject * src);
/* ASYNC_START */
GstMessage * gst_message_new_async_start (GstObject * src, gboolean new_base_time);
void gst_message_parse_async_start (GstMessage *message, gboolean *new_base_time);
GstMessage * gst_message_new_async_start (GstObject * src);
/* ASYNC_DONE */
GstMessage * gst_message_new_async_done (GstObject * src);
GstMessage * gst_message_new_async_done (GstObject * src, gboolean new_base_time);
void gst_message_parse_async_done (GstMessage *message, gboolean *new_base_time);
/* STRUCTURE CHANGE */
GstMessage * gst_message_new_structure_change (GstObject * src, GstStructureChangeType type,

View file

@ -548,11 +548,11 @@ gst_pipeline_handle_message (GstBin * bin, GstMessage * message)
GstPipeline *pipeline = GST_PIPELINE_CAST (bin);
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_ASYNC_START:
case GST_MESSAGE_ASYNC_DONE:
{
gboolean new_base_time;
gst_message_parse_async_start (message, &new_base_time);
gst_message_parse_async_done (message, &new_base_time);
/* reset our running time if we need to distribute a new base_time to the
* children. */

View file

@ -43,7 +43,7 @@ static const gchar *_quark_strings[] = {
"GstMessageBuffering", "GstMessageState", "GstMessageClockProvide",
"GstMessageClockLost", "GstMessageNewClock", "GstMessageStructureChange",
"GstMessageSegmentStart", "GstMessageSegmentDone", "GstMessageDuration",
"GstMessageAsyncStart", "GstMessageRequestState", "GstMessageStreamStatus",
"GstMessageAsyncDone", "GstMessageRequestState", "GstMessageStreamStatus",
"GstQueryPosition", "GstQueryDuration", "GstQueryLatency", "GstQueryConvert",
"GstQuerySegment", "GstQuerySeeking", "GstQueryFormats", "GstQueryBuffering",
"GstQueryURI", "GstEventStep", "GstMessageStepDone", "amount", "flush",

View file

@ -97,7 +97,7 @@ typedef enum _GstQuarkId
GST_QUARK_MESSAGE_SEGMENT_START = 68,
GST_QUARK_MESSAGE_SEGMENT_DONE = 69,
GST_QUARK_MESSAGE_DURATION = 70,
GST_QUARK_MESSAGE_ASYNC_START = 71,
GST_QUARK_MESSAGE_ASYNC_DONE = 71,
GST_QUARK_MESSAGE_REQUEST_STATE = 72,
GST_QUARK_MESSAGE_STREAM_STATUS = 73,
GST_QUARK_QUERY_POSITION = 74,

View file

@ -262,6 +262,8 @@ struct _GstBaseSinkPrivate
/* for throttling and QoS */
GstClockTime earliest_in_time;
GstClockTime throttle_time;
gboolean reset_time;
};
#define DO_RUNNING_AVG(avg,val,size) (((val) + ((size)-1) * (avg)) / (size))
@ -1469,6 +1471,7 @@ gst_base_sink_commit_state (GstBaseSink * basesink)
gboolean post_paused = FALSE;
gboolean post_async_done = FALSE;
gboolean post_playing = FALSE;
gboolean reset_time;
/* we are certainly not playing async anymore now */
basesink->playing_async = FALSE;
@ -1478,6 +1481,8 @@ gst_base_sink_commit_state (GstBaseSink * basesink)
next = GST_STATE_NEXT (basesink);
pending = GST_STATE_PENDING (basesink);
post_pending = pending;
reset_time = basesink->priv->reset_time;
basesink->priv->reset_time = FALSE;
switch (pending) {
case GST_STATE_PLAYING:
@ -1528,7 +1533,7 @@ gst_base_sink_commit_state (GstBaseSink * basesink)
if (post_async_done) {
GST_DEBUG_OBJECT (basesink, "posting async-done message");
gst_element_post_message (GST_ELEMENT_CAST (basesink),
gst_message_new_async_done (GST_OBJECT_CAST (basesink)));
gst_message_new_async_done (GST_OBJECT_CAST (basesink), reset_time));
}
if (post_playing) {
GST_DEBUG_OBJECT (basesink, "posting PLAYING state change message");
@ -3257,7 +3262,8 @@ gst_base_sink_flush_start (GstBaseSink * basesink, GstPad * pad)
* prerolled buffer */
basesink->playing_async = TRUE;
if (basesink->priv->async_enabled) {
gst_element_lost_state (GST_ELEMENT_CAST (basesink), TRUE);
basesink->priv->reset_time = TRUE;
gst_element_lost_state (GST_ELEMENT_CAST (basesink));
} else {
basesink->priv->have_latency = TRUE;
}
@ -3928,7 +3934,7 @@ gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event)
sink->playing_async = TRUE;
priv->pending_step.need_preroll = TRUE;
sink->need_preroll = FALSE;
gst_element_lost_state (GST_ELEMENT_CAST (sink), FALSE);
gst_element_lost_state (GST_ELEMENT_CAST (sink));
} else {
sink->priv->have_latency = TRUE;
sink->need_preroll = FALSE;
@ -4856,6 +4862,7 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
priv->step_unlock = FALSE;
basesink->need_preroll = TRUE;
basesink->playing_async = TRUE;
basesink->priv->reset_time = FALSE;
priv->current_sstart = GST_CLOCK_TIME_NONE;
priv->current_sstop = GST_CLOCK_TIME_NONE;
priv->eos_rtime = GST_CLOCK_TIME_NONE;
@ -4873,7 +4880,7 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
* the state change function */
ret = GST_STATE_CHANGE_ASYNC;
gst_element_post_message (GST_ELEMENT_CAST (basesink),
gst_message_new_async_start (GST_OBJECT_CAST (basesink), FALSE));
gst_message_new_async_start (GST_OBJECT_CAST (basesink)));
} else {
priv->have_latency = TRUE;
}
@ -4908,7 +4915,7 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
GST_DEBUG_OBJECT (basesink, "doing async state change");
ret = GST_STATE_CHANGE_ASYNC;
gst_element_post_message (GST_ELEMENT_CAST (basesink),
gst_message_new_async_start (GST_OBJECT_CAST (basesink), FALSE));
gst_message_new_async_start (GST_OBJECT_CAST (basesink)));
}
}
GST_BASE_SINK_PREROLL_UNLOCK (basesink);
@ -4970,8 +4977,7 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
GST_DEBUG_OBJECT (basesink, "doing async state change");
ret = GST_STATE_CHANGE_ASYNC;
gst_element_post_message (GST_ELEMENT_CAST (basesink),
gst_message_new_async_start (GST_OBJECT_CAST (basesink),
FALSE));
gst_message_new_async_start (GST_OBJECT_CAST (basesink)));
}
}
}
@ -5009,7 +5015,7 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
GST_STATE_PLAYING, GST_STATE_PAUSED, GST_STATE_READY));
gst_element_post_message (GST_ELEMENT_CAST (basesink),
gst_message_new_async_done (GST_OBJECT_CAST (basesink)));
gst_message_new_async_done (GST_OBJECT_CAST (basesink), FALSE));
}
priv->commited = TRUE;
} else {