From 0c205b96b4c92826311b0af4557704cf9822e36a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 18 May 2009 15:48:20 +0200 Subject: [PATCH] framestep: implement backwards framestep Update framestep document, we want to pass the flush flag in the step-done message. Add flush flag to the gstmessage. Update examples to use the new step-done message api. Implement framestep with playback rates < 0.0 too. --- docs/design/draft-framestep.txt | 12 +++++++--- gst/gstmessage.c | 29 +++++++++++++++--------- gst/gstmessage.h | 7 +++--- libs/gst/base/gstbasesink.c | 43 ++++++++++++++++++++++++------------ tests/examples/stepping/framestep1.c | 4 ++-- 5 files changed, 62 insertions(+), 33 deletions(-) diff --git a/docs/design/draft-framestep.txt b/docs/design/draft-framestep.txt index 56bceb0..8fe789e 100644 --- a/docs/design/draft-framestep.txt +++ b/docs/design/draft-framestep.txt @@ -180,13 +180,19 @@ messages "rate", G_TYPE_DOUBLE The rate and direction at which the frames were stepped. - "duration", G_TYPE_UINT64 - The total duration of the stepped units in GST_FORMAT_TIME. + "flush", G_TYPE_BOOLEAN + If the stepped frames were flushed. "intermediate", G_TYPE_BOOLEAN If this is an intermediate step operation that completed. - The message is emited by the element that performs the step operation. + "duration", G_TYPE_UINT64 + The total duration of the stepped units in GST_FORMAT_TIME. + + 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 + video sink element. Direction switch diff --git a/gst/gstmessage.c b/gst/gstmessage.c index fec9a19..4bc185d 100644 --- a/gst/gstmessage.c +++ b/gst/gstmessage.c @@ -1641,8 +1641,9 @@ gst_message_get_stream_status_object (GstMessage * message) * @format: the format of @amount * @amount: the amount of stepped data * @rate: the rate of the stepped amount - * @duration: the duration of the data + * @flush: is this an flushing step * @intermediate: is this an intermediate step + * @duration: the duration of the data * * This message is posted by elements when they complete a part, when @intermediate set * to TRUE, or a complete step operation. @@ -1658,7 +1659,7 @@ gst_message_get_stream_status_object (GstMessage * message) */ GstMessage * gst_message_new_step_done (GstObject * src, GstFormat format, guint64 amount, - gdouble rate, guint64 duration, gboolean intermediate) + gdouble rate, gboolean flush, gboolean intermediate, guint64 duration) { GstMessage *message; GstStructure *structure; @@ -1667,8 +1668,9 @@ gst_message_new_step_done (GstObject * src, GstFormat format, guint64 amount, GST_QUARK (FORMAT), GST_TYPE_FORMAT, format, GST_QUARK (AMOUNT), G_TYPE_UINT64, amount, GST_QUARK (RATE), G_TYPE_DOUBLE, rate, - GST_QUARK (DURATION), G_TYPE_UINT64, duration, - GST_QUARK (INTERMEDIATE), G_TYPE_BOOLEAN, intermediate, NULL); + GST_QUARK (FLUSH), G_TYPE_BOOLEAN, flush, + GST_QUARK (INTERMEDIATE), G_TYPE_BOOLEAN, intermediate, + GST_QUARK (DURATION), G_TYPE_UINT64, duration, NULL); message = gst_message_new_custom (GST_MESSAGE_STEP_DONE, src, structure); return message; @@ -1680,8 +1682,9 @@ gst_message_new_step_done (GstObject * src, GstFormat format, guint64 amount, * @format: result location for the format * @amount: result location for the amount * @rate: result location for the rate - * @duration: result location for the duration + * @flush: result location for the flush flag * @intermediate: result location for the intermediate flag + * @duration: result location for the duration * * Extract the requested state from the request_state message. * @@ -1691,8 +1694,8 @@ 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, guint64 * duration, - gboolean * intermediate) + guint64 * amount, gdouble * rate, gboolean * flush, gboolean * intermediate, + guint64 * duration) { g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STEP_DONE); @@ -1707,12 +1710,16 @@ gst_message_parse_step_done (GstMessage * message, GstFormat * format, if (rate) *rate = g_value_get_double (gst_structure_id_get_value (message->structure, GST_QUARK (RATE))); - if (duration) - *duration = - g_value_get_uint64 (gst_structure_id_get_value (message->structure, - GST_QUARK (DURATION))); + 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))); } diff --git a/gst/gstmessage.h b/gst/gstmessage.h index fe55aa5..48339b4 100644 --- a/gst/gstmessage.h +++ b/gst/gstmessage.h @@ -385,10 +385,11 @@ GstMessage * gst_message_new_state_dirty (GstObject * src); /* STEP_DONE */ GstMessage * gst_message_new_step_done (GstObject * src, GstFormat format, guint64 amount, - gdouble rate, guint64 duration, gboolean intermediate); + gdouble rate, gboolean flush, gboolean intermediate, + guint64 duration); void gst_message_parse_step_done (GstMessage * message, GstFormat *format, guint64 *amount, - gdouble *rate, guint64 *duration, gboolean *intermediate); - + gdouble *rate, gboolean *flush, gboolean *intermediate, + guint64 *duration); /* CLOCK_PROVIDE */ GstMessage * gst_message_new_clock_provide (GstObject * src, GstClock *clock, gboolean ready); void gst_message_parse_clock_provide (GstMessage *message, GstClock **clock, diff --git a/libs/gst/base/gstbasesink.c b/libs/gst/base/gstbasesink.c index 588224a..ca1135e 100644 --- a/libs/gst/base/gstbasesink.c +++ b/libs/gst/base/gstbasesink.c @@ -162,6 +162,7 @@ typedef struct guint64 duration; /* the duration in time of the skipped data */ guint64 start; /* running_time of the start */ gdouble rate; /* rate of skipping */ + gboolean flush; /* if this was a flushing step */ gboolean intermediate; /* if this is an intermediate step */ gboolean need_preroll; /* if we need preroll after this step */ } GstStepInfo; @@ -1476,22 +1477,23 @@ static void start_stepping (GstBaseSink * sink, GstSegment * segment, GstStepInfo * pending, GstStepInfo * current) { - gint64 start; - GST_DEBUG_OBJECT (sink, "update pending step"); memcpy (current, pending, sizeof (GstStepInfo)); pending->valid = FALSE; /* get the running time of the current segment start and remember it */ - start = - gst_segment_to_running_time (segment, segment->format, segment->start); + if (segment->rate > 0.0) + current->start = + gst_segment_to_running_time (segment, segment->format, segment->start); + else + current->start = + gst_segment_to_running_time (segment, segment->format, segment->stop); /* set the new rate */ - segment->rate = current->rate; + segment->rate = segment->rate * current->rate; GST_DEBUG_OBJECT (sink, "step started at running_time %" GST_TIME_FORMAT, - GST_TIME_ARGS (start)); - current->start = start; + GST_TIME_ARGS (current->start)); if (current->amount == -1) { GST_DEBUG_OBJECT (sink, "step amount == -1, stop stepping"); @@ -1517,26 +1519,38 @@ stop_stepping (GstBaseSink * sink, GstSegment * segment, GST_TIME_FORMAT, GST_TIME_ARGS (*rstart), GST_TIME_ARGS (cstart)); /* configure the duration of the elapsed segment */ - current->duration = *rstart - current->start; + if (segment->rate > 0.0) + current->duration = *rstart - current->start; + else + current->duration = *rstop - current->start; + GST_DEBUG_OBJECT (sink, "step elapsed running_time %" GST_TIME_FORMAT, GST_TIME_ARGS (current->duration)); /* update the segment, discarding what was consumed, running time goes * backwards with the duration of the data we skipped. FIXME, this only works * in PAUSED. */ - segment->time = gst_segment_to_stream_time (segment, segment->format, cstart); - segment->start = cstart; + if (segment->rate > 0.0) { + segment->time = + gst_segment_to_stream_time (segment, segment->format, cstart); + segment->start = cstart; + + *rstart = current->start; + *rstop -= current->duration; + } else { + segment->stop = cstop; + *rstop = current->start; + *rstart -= current->duration; + } segment->accum = current->start; /* the clip segment is used for position report in paused... */ memcpy (sink->abidata.ABI.clip_segment, segment, sizeof (GstSegment)); - *rstart = current->start; - *rstop -= current->duration; - message = gst_message_new_step_done (GST_OBJECT_CAST (sink), current->format, - current->amount, current->rate, current->duration, current->intermediate); + current->amount, current->rate, current->flush, current->intermediate, + current->duration); gst_message_set_seqnum (message, current->seqnum); gst_element_post_message (GST_ELEMENT_CAST (sink), message); @@ -3392,6 +3406,7 @@ gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event) priv->pending_step.amount = amount; priv->pending_step.position = 0; priv->pending_step.rate = rate; + priv->pending_step.flush = flush; priv->pending_step.intermediate = intermediate; priv->pending_step.valid = TRUE; diff --git a/tests/examples/stepping/framestep1.c b/tests/examples/stepping/framestep1.c index 9625f78..ddf82a2 100644 --- a/tests/examples/stepping/framestep1.c +++ b/tests/examples/stepping/framestep1.c @@ -37,11 +37,11 @@ event_loop (GstElement * pipe) GstFormat format; guint64 amount; gdouble rate; + gboolean flush, intermediate; guint64 duration; - gboolean intermediate; gst_message_parse_step_done (message, &format, &amount, &rate, - &duration, &intermediate); + &flush, &intermediate, &duration); if (format == GST_FORMAT_DEFAULT) { g_message ("step done: %" GST_TIME_FORMAT " skipped in %" -- 2.7.4