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.
This commit is contained in:
Wim Taymans 2009-05-18 15:48:20 +02:00 committed by Wim Taymans
parent 1839782379
commit 0c205b96b4
5 changed files with 62 additions and 33 deletions

View file

@ -180,13 +180,19 @@ messages
"rate", G_TYPE_DOUBLE "rate", G_TYPE_DOUBLE
The rate and direction at which the frames were stepped. The rate and direction at which the frames were stepped.
"duration", G_TYPE_UINT64 "flush", G_TYPE_BOOLEAN
The total duration of the stepped units in GST_FORMAT_TIME. If the stepped frames were flushed.
"intermediate", G_TYPE_BOOLEAN "intermediate", G_TYPE_BOOLEAN
If this is an intermediate step operation that completed. 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 Direction switch

View file

@ -1641,8 +1641,9 @@ gst_message_get_stream_status_object (GstMessage * message)
* @format: the format of @amount * @format: the format of @amount
* @amount: the amount of stepped data * @amount: the amount of stepped data
* @rate: the rate of the stepped amount * @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 * @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 * This message is posted by elements when they complete a part, when @intermediate set
* to TRUE, or a complete step operation. * to TRUE, or a complete step operation.
@ -1658,7 +1659,7 @@ gst_message_get_stream_status_object (GstMessage * message)
*/ */
GstMessage * GstMessage *
gst_message_new_step_done (GstObject * src, GstFormat format, guint64 amount, 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; GstMessage *message;
GstStructure *structure; 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 (FORMAT), GST_TYPE_FORMAT, format,
GST_QUARK (AMOUNT), G_TYPE_UINT64, amount, GST_QUARK (AMOUNT), G_TYPE_UINT64, amount,
GST_QUARK (RATE), G_TYPE_DOUBLE, rate, GST_QUARK (RATE), G_TYPE_DOUBLE, rate,
GST_QUARK (DURATION), G_TYPE_UINT64, duration, GST_QUARK (FLUSH), G_TYPE_BOOLEAN, flush,
GST_QUARK (INTERMEDIATE), G_TYPE_BOOLEAN, intermediate, NULL); 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); message = gst_message_new_custom (GST_MESSAGE_STEP_DONE, src, structure);
return message; return message;
@ -1680,8 +1682,9 @@ gst_message_new_step_done (GstObject * src, GstFormat format, guint64 amount,
* @format: result location for the format * @format: result location for the format
* @amount: result location for the amount * @amount: result location for the amount
* @rate: result location for the rate * @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 * @intermediate: result location for the intermediate flag
* @duration: result location for the duration
* *
* Extract the requested state from the request_state message. * 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 void
gst_message_parse_step_done (GstMessage * message, GstFormat * format, gst_message_parse_step_done (GstMessage * message, GstFormat * format,
guint64 * amount, gdouble * rate, guint64 * duration, guint64 * amount, gdouble * rate, gboolean * flush, gboolean * intermediate,
gboolean * intermediate) guint64 * duration)
{ {
g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_IS_MESSAGE (message));
g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STEP_DONE); 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) if (rate)
*rate = g_value_get_double (gst_structure_id_get_value (message->structure, *rate = g_value_get_double (gst_structure_id_get_value (message->structure,
GST_QUARK (RATE))); GST_QUARK (RATE)));
if (duration) if (flush)
*duration = *flush =
g_value_get_uint64 (gst_structure_id_get_value (message->structure, g_value_get_boolean (gst_structure_id_get_value (message->structure,
GST_QUARK (DURATION))); GST_QUARK (FLUSH)));
if (intermediate) if (intermediate)
*intermediate = *intermediate =
g_value_get_boolean (gst_structure_id_get_value (message->structure, g_value_get_boolean (gst_structure_id_get_value (message->structure,
GST_QUARK (INTERMEDIATE))); GST_QUARK (INTERMEDIATE)));
if (duration)
*duration =
g_value_get_uint64 (gst_structure_id_get_value (message->structure,
GST_QUARK (DURATION)));
} }

View file

@ -385,10 +385,11 @@ GstMessage * gst_message_new_state_dirty (GstObject * src);
/* STEP_DONE */ /* STEP_DONE */
GstMessage * gst_message_new_step_done (GstObject * src, GstFormat format, guint64 amount, 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, 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 */ /* CLOCK_PROVIDE */
GstMessage * gst_message_new_clock_provide (GstObject * src, GstClock *clock, gboolean ready); GstMessage * gst_message_new_clock_provide (GstObject * src, GstClock *clock, gboolean ready);
void gst_message_parse_clock_provide (GstMessage *message, GstClock **clock, void gst_message_parse_clock_provide (GstMessage *message, GstClock **clock,

View file

@ -162,6 +162,7 @@ typedef struct
guint64 duration; /* the duration in time of the skipped data */ guint64 duration; /* the duration in time of the skipped data */
guint64 start; /* running_time of the start */ guint64 start; /* running_time of the start */
gdouble rate; /* rate of skipping */ gdouble rate; /* rate of skipping */
gboolean flush; /* if this was a flushing step */
gboolean intermediate; /* if this is an intermediate step */ gboolean intermediate; /* if this is an intermediate step */
gboolean need_preroll; /* if we need preroll after this step */ gboolean need_preroll; /* if we need preroll after this step */
} GstStepInfo; } GstStepInfo;
@ -1476,22 +1477,23 @@ static void
start_stepping (GstBaseSink * sink, GstSegment * segment, start_stepping (GstBaseSink * sink, GstSegment * segment,
GstStepInfo * pending, GstStepInfo * current) GstStepInfo * pending, GstStepInfo * current)
{ {
gint64 start;
GST_DEBUG_OBJECT (sink, "update pending step"); GST_DEBUG_OBJECT (sink, "update pending step");
memcpy (current, pending, sizeof (GstStepInfo)); memcpy (current, pending, sizeof (GstStepInfo));
pending->valid = FALSE; pending->valid = FALSE;
/* get the running time of the current segment start and remember it */ /* get the running time of the current segment start and remember it */
start = if (segment->rate > 0.0)
current->start =
gst_segment_to_running_time (segment, segment->format, segment->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 */ /* 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_DEBUG_OBJECT (sink, "step started at running_time %" GST_TIME_FORMAT,
GST_TIME_ARGS (start)); GST_TIME_ARGS (current->start));
current->start = start;
if (current->amount == -1) { if (current->amount == -1) {
GST_DEBUG_OBJECT (sink, "step amount == -1, stop stepping"); 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)); GST_TIME_FORMAT, GST_TIME_ARGS (*rstart), GST_TIME_ARGS (cstart));
/* configure the duration of the elapsed segment */ /* configure the duration of the elapsed segment */
if (segment->rate > 0.0)
current->duration = *rstart - current->start; current->duration = *rstart - current->start;
else
current->duration = *rstop - current->start;
GST_DEBUG_OBJECT (sink, "step elapsed running_time %" GST_TIME_FORMAT, GST_DEBUG_OBJECT (sink, "step elapsed running_time %" GST_TIME_FORMAT,
GST_TIME_ARGS (current->duration)); GST_TIME_ARGS (current->duration));
/* update the segment, discarding what was consumed, running time goes /* update the segment, discarding what was consumed, running time goes
* backwards with the duration of the data we skipped. FIXME, this only works * backwards with the duration of the data we skipped. FIXME, this only works
* in PAUSED. */ * in PAUSED. */
segment->time = gst_segment_to_stream_time (segment, segment->format, cstart); if (segment->rate > 0.0) {
segment->time =
gst_segment_to_stream_time (segment, segment->format, cstart);
segment->start = cstart; segment->start = cstart;
*rstart = current->start;
*rstop -= current->duration;
} else {
segment->stop = cstop;
*rstop = current->start;
*rstart -= current->duration;
}
segment->accum = current->start; segment->accum = current->start;
/* the clip segment is used for position report in paused... */ /* the clip segment is used for position report in paused... */
memcpy (sink->abidata.ABI.clip_segment, segment, sizeof (GstSegment)); memcpy (sink->abidata.ABI.clip_segment, segment, sizeof (GstSegment));
*rstart = current->start;
*rstop -= current->duration;
message = message =
gst_message_new_step_done (GST_OBJECT_CAST (sink), current->format, 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_message_set_seqnum (message, current->seqnum);
gst_element_post_message (GST_ELEMENT_CAST (sink), message); 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.amount = amount;
priv->pending_step.position = 0; priv->pending_step.position = 0;
priv->pending_step.rate = rate; priv->pending_step.rate = rate;
priv->pending_step.flush = flush;
priv->pending_step.intermediate = intermediate; priv->pending_step.intermediate = intermediate;
priv->pending_step.valid = TRUE; priv->pending_step.valid = TRUE;

View file

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