From 25067558dc07096bb9ae7a3184e5517961ed9a9f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 12 Jun 2009 13:18:21 +0200 Subject: [PATCH] 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. --- docs/design/draft-framestep.txt | 36 ++++++++++++++++++++ gst/gstmessage.c | 64 ++++++++++++++++++------------------ gst/gstmessage.h | 12 ++++--- gst/gstquark.c | 2 +- gst/gstquark.h | 3 +- libs/gst/base/gstbasesink.c | 52 +++++++++++++++++++++-------- tests/examples/stepping/framestep1.c | 3 +- 7 files changed, 119 insertions(+), 53 deletions(-) diff --git a/docs/design/draft-framestep.txt b/docs/design/draft-framestep.txt index cdc064b..f76518e 100644 --- a/docs/design/draft-framestep.txt +++ b/docs/design/draft-framestep.txt @@ -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 diff --git a/gst/gstmessage.c b/gst/gstmessage.c index c8f042b..fa4606a 100644 --- a/gst/gstmessage.c +++ b/gst/gstmessage.c @@ -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); } diff --git a/gst/gstmessage.h b/gst/gstmessage.h index 9103669..fa06e3a 100644 --- a/gst/gstmessage.h +++ b/gst/gstmessage.h @@ -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, diff --git a/gst/gstquark.c b/gst/gstquark.c index 6a898b3..957f43c 100644 --- a/gst/gstquark.c +++ b/gst/gstquark.c @@ -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]; diff --git a/gst/gstquark.h b/gst/gstquark.h index ec48893..234883e 100644 --- a/gst/gstquark.h +++ b/gst/gstquark.h @@ -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]; diff --git a/libs/gst/base/gstbasesink.c b/libs/gst/base/gstbasesink.c index 91197eb..a0b9d48 100644 --- a/libs/gst/base/gstbasesink.c +++ b/libs/gst/base/gstbasesink.c @@ -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) { diff --git a/tests/examples/stepping/framestep1.c b/tests/examples/stepping/framestep1.c index ddf82a2..e188284 100644 --- a/tests/examples/stepping/framestep1.c +++ b/tests/examples/stepping/framestep1.c @@ -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 %" -- 2.7.4