stepping: more stepping improvements

Update design doc with step-start docs.
Add eos field to step done message
when stepping in reverse, update the segment time field.
Flush out the current step when we are flushing.
This commit is contained in:
Wim Taymans 2009-06-12 13:18:21 +02:00
parent 23b772664b
commit 25067558dc
7 changed files with 119 additions and 53 deletions

View file

@ -170,6 +170,39 @@ events
messages
--------
A GST_MESSAGE_STEP_START is created. It contains the following fields.
"active"
If the step was queued or activated.
"format", GST_TYPE_FORMAT
The format of the step units that queued/activated.
"amount", G_TYPE_UINT64
The amount of units that were queued/activated.
"rate", G_TYPE_DOUBLE
The rate and direction at which the frames were queued/activated.
"flush", G_TYPE_BOOLEAN
If the queued/activated frames will be flushed.
"intermediate", G_TYPE_BOOLEAN
If this is an intermediate step operation that queued/activated.
The STEP_START message is emited 2 times:
* first when an element received the STEP event and queued it. The "active"
field will be FALSE in this case.
* second when the step operation started in the streaming thread. The "active"
field is TRUE in this case. After this message is emited, the application
can queue a new step operation.
The purpose of this message is to find out how many elements participate in the
step operation and to queue new step operations at the earliest possible
moment.
A new GST_MESSAGE_STEP_DONE message is created. It contains the following
fields:
@ -191,6 +224,9 @@ messages
"duration", G_TYPE_UINT64
The total duration of the stepped units in GST_FORMAT_TIME.
"eos", G_TYPE_BOOLEAN
The step ended because of EOS.
The message is emited by the element that performs the step operation. The
purpose is to return the duration in GST_FORMAT_TIME of the stepped media. This
especially interesting to align other stream in case of stepping frames on the

View file

@ -1645,6 +1645,7 @@ gst_message_get_stream_status_object (GstMessage * message)
* @flush: is this an flushing step
* @intermediate: is this an intermediate step
* @duration: the duration of the data
* @eos: the step caused EOS
*
* This message is posted by elements when they complete a part, when @intermediate set
* to TRUE, or a complete step operation.
@ -1660,7 +1661,8 @@ gst_message_get_stream_status_object (GstMessage * message)
*/
GstMessage *
gst_message_new_step_done (GstObject * src, GstFormat format, guint64 amount,
gdouble rate, gboolean flush, gboolean intermediate, guint64 duration)
gdouble rate, gboolean flush, gboolean intermediate, guint64 duration,
gboolean eos)
{
GstMessage *message;
GstStructure *structure;
@ -1671,7 +1673,8 @@ gst_message_new_step_done (GstObject * src, GstFormat format, guint64 amount,
GST_QUARK (RATE), G_TYPE_DOUBLE, rate,
GST_QUARK (FLUSH), G_TYPE_BOOLEAN, flush,
GST_QUARK (INTERMEDIATE), G_TYPE_BOOLEAN, intermediate,
GST_QUARK (DURATION), G_TYPE_UINT64, duration, NULL);
GST_QUARK (DURATION), G_TYPE_UINT64, duration,
GST_QUARK (EOS), G_TYPE_BOOLEAN, eos, NULL);
message = gst_message_new_custom (GST_MESSAGE_STEP_DONE, src, structure);
return message;
@ -1686,6 +1689,7 @@ gst_message_new_step_done (GstObject * src, GstFormat format, guint64 amount,
* @flush: result location for the flush flag
* @intermediate: result location for the intermediate flag
* @duration: result location for the duration
* @eos: result location for the EOS flag
*
* Extract the requested state from the request_state message.
*
@ -1696,56 +1700,52 @@ gst_message_new_step_done (GstObject * src, GstFormat format, guint64 amount,
void
gst_message_parse_step_done (GstMessage * message, GstFormat * format,
guint64 * amount, gdouble * rate, gboolean * flush, gboolean * intermediate,
guint64 * duration)
guint64 * duration, gboolean * eos)
{
g_return_if_fail (GST_IS_MESSAGE (message));
g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STEP_DONE);
if (format)
*format = g_value_get_enum (gst_structure_id_get_value (message->structure,
GST_QUARK (FORMAT)));
if (amount)
*amount =
g_value_get_uint64 (gst_structure_id_get_value (message->structure,
GST_QUARK (AMOUNT)));
if (rate)
*rate = g_value_get_double (gst_structure_id_get_value (message->structure,
GST_QUARK (RATE)));
if (flush)
*flush =
g_value_get_boolean (gst_structure_id_get_value (message->structure,
GST_QUARK (FLUSH)));
if (intermediate)
*intermediate =
g_value_get_boolean (gst_structure_id_get_value (message->structure,
GST_QUARK (INTERMEDIATE)));
if (duration)
*duration =
g_value_get_uint64 (gst_structure_id_get_value (message->structure,
GST_QUARK (DURATION)));
gst_structure_id_get (message->structure,
GST_QUARK (FORMAT), GST_TYPE_FORMAT, format,
GST_QUARK (AMOUNT), G_TYPE_UINT64, amount,
GST_QUARK (RATE), G_TYPE_DOUBLE, rate,
GST_QUARK (FLUSH), G_TYPE_BOOLEAN, flush,
GST_QUARK (INTERMEDIATE), G_TYPE_BOOLEAN, intermediate,
GST_QUARK (EOS), G_TYPE_BOOLEAN, eos, NULL);
}
GstMessage *
gst_message_new_step_start (GstObject * src, gboolean active)
gst_message_new_step_start (GstObject * src, gboolean active, GstFormat format,
guint64 amount, gdouble rate, gboolean flush, gboolean intermediate)
{
GstMessage *message;
GstStructure *structure;
structure = gst_structure_id_new (GST_QUARK (MESSAGE_STEP_START),
GST_QUARK (ACTIVE), G_TYPE_BOOLEAN, active, NULL);
GST_QUARK (ACTIVE), G_TYPE_BOOLEAN, active,
GST_QUARK (FORMAT), GST_TYPE_FORMAT, format,
GST_QUARK (AMOUNT), G_TYPE_UINT64, amount,
GST_QUARK (RATE), G_TYPE_DOUBLE, rate,
GST_QUARK (FLUSH), G_TYPE_BOOLEAN, flush,
GST_QUARK (INTERMEDIATE), G_TYPE_BOOLEAN, intermediate, NULL);
message = gst_message_new_custom (GST_MESSAGE_STEP_START, src, structure);
return message;
}
void
gst_message_parse_step_start (GstMessage * message, gboolean * active)
gst_message_parse_step_start (GstMessage * message, gboolean * active,
GstFormat * format, guint64 * amount, gdouble * rate, gboolean * flush,
gboolean * intermediate)
{
g_return_if_fail (GST_IS_MESSAGE (message));
g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STEP_START);
if (active)
*active =
g_value_get_boolean (gst_structure_id_get_value (message->structure,
GST_QUARK (ACTIVE)));
gst_structure_id_get (message->structure,
GST_QUARK (ACTIVE), G_TYPE_BOOLEAN, active,
GST_QUARK (FORMAT), GST_TYPE_FORMAT, format,
GST_QUARK (AMOUNT), G_TYPE_UINT64, amount,
GST_QUARK (RATE), G_TYPE_DOUBLE, rate,
GST_QUARK (FLUSH), G_TYPE_BOOLEAN, flush,
GST_QUARK (INTERMEDIATE), G_TYPE_BOOLEAN, intermediate, NULL);
}

View file

@ -399,10 +399,10 @@ GstMessage * gst_message_new_state_dirty (GstObject * src);
/* STEP_DONE */
GstMessage * gst_message_new_step_done (GstObject * src, GstFormat format, guint64 amount,
gdouble rate, gboolean flush, gboolean intermediate,
guint64 duration);
guint64 duration, gboolean eos);
void gst_message_parse_step_done (GstMessage * message, GstFormat *format, guint64 *amount,
gdouble *rate, gboolean *flush, gboolean *intermediate,
guint64 *duration);
guint64 *duration, gboolean *eos);
/* CLOCK_PROVIDE */
GstMessage * gst_message_new_clock_provide (GstObject * src, GstClock *clock, gboolean ready);
void gst_message_parse_clock_provide (GstMessage *message, GstClock **clock,
@ -466,8 +466,12 @@ GstMessage * gst_message_new_request_state (GstObject * src, GstState state
void gst_message_parse_request_state (GstMessage * message, GstState *state);
/* STEP_START */
GstMessage * gst_message_new_step_start (GstObject * src, gboolean active);
void gst_message_parse_step_start (GstMessage * message, gboolean *active);
GstMessage * gst_message_new_step_start (GstObject * src, gboolean active, GstFormat format,
guint64 amount, gdouble rate, gboolean flush,
gboolean intermediate);
void gst_message_parse_step_start (GstMessage * message, gboolean *active, GstFormat *format,
guint64 *amount, gdouble *rate, gboolean *flush,
gboolean *intermediate);
/* custom messages */
GstMessage * gst_message_new_custom (GstMessageType type,

View file

@ -47,7 +47,7 @@ static const gchar *_quark_strings[] = {
"GstQueryPosition", "GstQueryDuration", "GstQueryLatency", "GstQueryConvert",
"GstQuerySegment", "GstQuerySeeking", "GstQueryFormats", "GstQueryBuffering",
"GstQueryURI", "GstEventStep", "GstMessageStepDone", "amount", "flush",
"intermediate", "GstMessageStepStart", "active"
"intermediate", "GstMessageStepStart", "active", "eos"
};
GQuark _priv_gst_quark_table[GST_QUARK_MAX];

View file

@ -116,8 +116,9 @@ typedef enum _GstQuarkId
GST_QUARK_INTERMEDIATE = 87,
GST_QUARK_MESSAGE_STEP_START = 88,
GST_QUARK_ACTIVE = 89,
GST_QUARK_EOS = 90,
GST_QUARK_MAX = 90
GST_QUARK_MAX = 91
} GstQuarkId;
extern GQuark _priv_gst_quark_table[GST_QUARK_MAX];

View file

@ -1495,7 +1495,9 @@ start_stepping (GstBaseSink * sink, GstSegment * segment,
GST_OBJECT_UNLOCK (sink);
/* post message first */
message = gst_message_new_step_start (GST_OBJECT (sink), TRUE);
message =
gst_message_new_step_start (GST_OBJECT (sink), TRUE, current->format,
current->amount, current->rate, current->flush, current->intermediate);
gst_message_set_seqnum (message, current->seqnum);
gst_element_post_message (GST_ELEMENT (sink), message);
@ -1518,16 +1520,28 @@ start_stepping (GstBaseSink * sink, GstSegment * segment,
end = current->start + current->amount;
if (!current->flush) {
/* update the segment clipping regions for non-flushing seeks */
if (segment->rate > 0.0)
if (segment->rate > 0.0) {
segment->stop = gst_segment_to_position (segment, GST_FORMAT_TIME, end);
else
segment->start =
gst_segment_to_position (segment, GST_FORMAT_TIME, end);
segment->last_stop = segment->stop;
} else {
gint64 position;
position = gst_segment_to_position (segment, GST_FORMAT_TIME, end);
segment->time = position;
segment->start = position;
segment->last_stop = position;
}
}
}
GST_DEBUG_OBJECT (sink, "segment now %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
GST_TIME_ARGS (segment->start), GST_TIME_ARGS (segment->stop));
GST_DEBUG_OBJECT (sink,
"segment now rate %lf, applied rate %lf, "
"format GST_FORMAT_TIME, "
"%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT
", time %" GST_TIME_FORMAT ", accum %" GST_TIME_FORMAT,
segment->rate, segment->applied_rate, GST_TIME_ARGS (segment->start),
GST_TIME_ARGS (segment->stop), GST_TIME_ARGS (segment->time),
GST_TIME_ARGS (segment->accum));
GST_DEBUG_OBJECT (sink, "step started at running_time %" GST_TIME_FORMAT,
GST_TIME_ARGS (current->start));
@ -1544,7 +1558,7 @@ start_stepping (GstBaseSink * sink, GstSegment * segment,
static void
stop_stepping (GstBaseSink * sink, GstSegment * segment,
GstStepInfo * current, gint64 rstart, gint64 rstop)
GstStepInfo * current, gint64 rstart, gint64 rstop, gboolean eos)
{
gint64 stop, position;
GstMessage *message;
@ -1596,7 +1610,7 @@ stop_stepping (GstBaseSink * sink, GstSegment * segment,
message =
gst_message_new_step_done (GST_OBJECT_CAST (sink), current->format,
current->amount, current->rate, current->flush, current->intermediate,
current->duration);
current->duration, eos);
gst_message_set_seqnum (message, current->seqnum);
gst_element_post_message (GST_ELEMENT_CAST (sink), message);
@ -1711,6 +1725,7 @@ gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
GstClockTime sstart, sstop; /* clipped timestamps converted to stream time */
GstFormat format;
GstBaseSinkPrivate *priv;
gboolean eos;
priv = basesink->priv;
@ -1746,6 +1761,7 @@ gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
GST_TIME_ARGS (rstart));
/* if we are stepping, we end now */
*step_end = step->valid;
eos = TRUE;
goto eos_done;
}
default:
@ -1759,6 +1775,8 @@ gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
}
}
eos = FALSE;
/* else do buffer sync code */
buffer = GST_BUFFER_CAST (obj);
@ -1799,6 +1817,7 @@ gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
if (G_UNLIKELY (!gst_segment_clip (segment, GST_FORMAT_TIME,
(gint64) start, (gint64) stop, &cstart, &cstop))) {
if (step->valid) {
GST_DEBUG_OBJECT (basesink, "step out of segment");
/* when we are stepping, pretend we're at the end of the segment */
if (segment->rate > 0.0) {
cstart = segment->stop;
@ -1841,10 +1860,10 @@ do_times:
sstop = gst_segment_to_stream_time (segment, format, cstop);
eos_done:
/* done label only called when doing EOS, we also stop stepping then */
/* eos_done label only called when doing EOS, we also stop stepping then */
if (*step_end && step->flush) {
GST_DEBUG_OBJECT (basesink, "flushing step ended");
stop_stepping (basesink, segment, step, rstart, rstop);
stop_stepping (basesink, segment, step, rstart, rstop, eos);
*step_end = FALSE;
}
@ -2326,6 +2345,7 @@ flushing:
preroll_failed:
{
GST_DEBUG_OBJECT (basesink, "preroll failed");
*step_end = FALSE;
return ret;
}
}
@ -2674,6 +2694,9 @@ again:
if (ret == GST_FLOW_STEP)
goto again;
if (G_UNLIKELY (basesink->flushing))
goto flushing;
priv->rendered++;
}
} else {
@ -2739,7 +2762,7 @@ done:
/* the step ended, check if we need to activate a new step */
GST_DEBUG_OBJECT (basesink, "step ended");
stop_stepping (basesink, &basesink->segment, &priv->current_step,
priv->current_rstart, priv->current_rstop);
priv->current_rstart, priv->current_rstop, basesink->eos);
goto again;
}
@ -3550,8 +3573,9 @@ gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event)
current = &priv->current_step;
/* post message first */
message = gst_message_new_step_start (GST_OBJECT (sink), FALSE);
gst_message_set_seqnum (message, current->seqnum);
message = gst_message_new_step_start (GST_OBJECT (sink), FALSE, format,
amount, rate, flush, intermediate);
gst_message_set_seqnum (message, seqnum);
gst_element_post_message (GST_ELEMENT (sink), message);
if (flush) {

View file

@ -39,9 +39,10 @@ event_loop (GstElement * pipe)
gdouble rate;
gboolean flush, intermediate;
guint64 duration;
gboolean eos;
gst_message_parse_step_done (message, &format, &amount, &rate,
&flush, &intermediate, &duration);
&flush, &intermediate, &duration, &eos);
if (format == GST_FORMAT_DEFAULT) {
g_message ("step done: %" GST_TIME_FORMAT " skipped in %"