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
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

View file

@ -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)));
}

View file

@ -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,

View file

@ -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;

View file

@ -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 %"