summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: cb9597a)
raw | patch | inline | side by side (parent: cb9597a)
author | Wim Taymans <wim.taymans@collabora.co.uk> | |
Thu, 14 May 2009 17:29:08 +0000 (19:29 +0200) | ||
committer | Wim Taymans <wim@metal.(none)> | |
Mon, 1 Jun 2009 11:37:27 +0000 (13:37 +0200) |
Make start and stop_stepping methods and move their invocation in the right
places.
Perform the atual stepping operation where we have full context about the
timestamps.
places.
Perform the atual stepping operation where we have full context about the
timestamps.
libs/gst/base/gstbasesink.c | patch | blob | history |
index cf19be215ee4125aaf5f396a48f216bb51d05369..398042fd718a23748cadcf5aef7a958b4c2a84e8 100644 (file)
typedef struct
{
- guint cookie;
- guint32 seqnum;
- GstFormat format;
- guint64 remaining;
- guint64 amount;
- guint64 duration;
- gdouble rate;
- gboolean intermediate;
- gboolean need_preroll;
+ gboolean valid; /* if this info is valid */
+ guint32 seqnum; /* the seqnum of the STEP event */
+ GstFormat format; /* the format of the amount */
+ guint64 amount; /* the total amount of data to skip */
+ guint64 remaining; /* the remaining amount of data to skip */
+ guint64 duration; /* the duration in time of the skipped data */
+ guint64 start; /* running_time of the start */
+ gdouble rate; /* rate of skipping */
+ gboolean intermediate; /* if this is an intermediate step */
+ gboolean need_preroll; /* if we need preroll after this step */
} GstStepInfo;
/* FIXME, some stuff in ABI.data and other in Private...
gboolean call_preroll;
- GstStepInfo step;
+ /* we have a pending and a current step operation */
+ GstStepInfo current_step;
+ GstStepInfo pending_step;
};
#define DO_RUNNING_AVG(avg,val,size) (((val) + ((size)-1) * (avg)) / (size))
}
}
+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);
+
+ /* update the segment, accumulating what was consumed at the old rate, setting
+ * the new rate. */
+ gst_segment_set_newsegment_full (segment, TRUE, current->rate,
+ segment->applied_rate, segment->format, segment->start, segment->stop,
+ segment->time);
+
+ GST_DEBUG_OBJECT (sink, "step start %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (start));
+ current->start = start;
+}
+
+static void
+stop_stepping (GstBaseSink * sink, GstSegment * segment,
+ GstStepInfo * current, gint64 * cstart, gint64 * cstop)
+{
+ GstMessage *message;
+ gint64 stop;
+
+ GST_DEBUG_OBJECT (sink, "step complete");
+
+ /* get the end of the step segment */
+ stop = gst_segment_to_running_time (segment, segment->format, *cstart);
+
+ GST_DEBUG_OBJECT (sink, "step stop %" GST_TIME_FORMAT, GST_TIME_ARGS (stop));
+ /* configure the duration of the elapsed segment */
+ current->duration = stop - current->start;
+
+ /* update the segment, discarding what was consumed */
+ segment->start = *cstart;
+
+ message =
+ gst_message_new_step_done (GST_OBJECT_CAST (sink), current->format,
+ current->amount, current->rate, current->duration, current->intermediate);
+ gst_message_set_seqnum (message, current->seqnum);
+ gst_element_post_message (GST_ELEMENT_CAST (sink), message);
+
+ if (!current->intermediate)
+ sink->need_preroll = current->need_preroll;
+ current->valid = FALSE;
+}
+
+static gboolean
+handle_stepping (GstBaseSink * sink, GstSegment * segment,
+ GstStepInfo * current)
+{
+ GstBaseSinkPrivate *priv;
+ gboolean step_end = FALSE;
+
+ priv = sink->priv;
+
+ /* see if we need to skip this buffer because of stepping */
+ switch (current->format) {
+ case GST_FORMAT_TIME:
+ GST_DEBUG_OBJECT (sink,
+ "got time step %" GST_TIME_FORMAT "/%" GST_TIME_FORMAT,
+ GST_TIME_ARGS (current->remaining), GST_TIME_ARGS (current->amount));
+ break;
+ case GST_FORMAT_BUFFERS:
+ GST_DEBUG_OBJECT (sink,
+ "got default step %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
+ current->remaining, current->amount);
+
+ if (current->remaining > 0) {
+ current->remaining--;
+ } else {
+ step_end = TRUE;
+ }
+ break;
+ case GST_FORMAT_DEFAULT:
+ default:
+ GST_DEBUG_OBJECT (sink,
+ "got unknown step %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
+ current->remaining, current->amount);
+ break;
+ }
+ return step_end;
+}
/* with STREAM_LOCK, PREROLL_LOCK
*
gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
GstClockTime * rsstart, GstClockTime * rsstop,
GstClockTime * rrstart, GstClockTime * rrstop, gboolean * do_sync,
- GstSegment * segment)
+ gboolean * stepped, GstSegment * segment, GstStepInfo * step)
{
GstBaseSinkClass *bclass;
GstBuffer *buffer;
GstClockTime sstart, sstop; /* clipped timestamps converted to stream time */
GstFormat format;
GstBaseSinkPrivate *priv;
+ gboolean step_end;
priv = basesink->priv;
/* start with nothing */
start = stop = -1;
+ step_end = FALSE;
+
if (G_UNLIKELY (GST_IS_EVENT (obj))) {
GstEvent *event = GST_EVENT_CAST (obj);
*do_sync = rstart != -1;
GST_DEBUG_OBJECT (basesink, "sync times for EOS %" GST_TIME_FORMAT,
GST_TIME_ARGS (rstart));
+ /* if we are stepping, we end now */
+ step_end = step->valid;
goto done;
}
default:
bclass = GST_BASE_SINK_GET_CLASS (basesink);
- /* just get the times to see if we need syncing */
+ /* just get the times to see if we need syncing, if the start returns -1 we
+ * don't sync. */
if (bclass->get_times)
bclass->get_times (basesink, buffer, &start, &stop);
if (start == -1) {
+ /* we don't need to sync but we still want to get the timestamps for
+ * tracking the position */
gst_base_sink_get_times (basesink, buffer, &start, &stop);
*do_sync = FALSE;
} else {
/* collect segment and format for code clarity */
format = segment->format;
- /* no timestamp clipping if we did not * get a TIME segment format */
+ /* no timestamp clipping if we did not get a TIME segment format */
if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
cstart = start;
cstop = stop;
rstart = gst_segment_to_running_time (segment, format, cstart);
rstop = gst_segment_to_running_time (segment, format, cstop);
+ if (G_UNLIKELY (step->valid)) {
+ if (!(step_end = handle_stepping (basesink, segment, step)))
+ *stepped = TRUE;
+ }
+
done:
+ /* done label called when doing EOS */
+ if (step_end)
+ stop_stepping (basesink, segment, &priv->current_step, &cstart, &cstop);
+
/* save times */
*rsstart = sstart;
*rsstop = sstop;
}
}
-static gboolean
-handle_stepping (GstBaseSink * basesink)
-{
- GstBaseSinkPrivate *priv;
-
- priv = basesink->priv;
-
- /* see if we need to skip this buffer because of stepping */
- if (priv->step.remaining != -1) {
- GstMessage *message;
- GstStepInfo *step;
-
- step = &priv->step;
-
- switch (step->format) {
- case GST_FORMAT_TIME:
- GST_DEBUG_OBJECT (basesink,
- "got time step %" GST_TIME_FORMAT "/%" GST_TIME_FORMAT,
- GST_TIME_ARGS (step->remaining), GST_TIME_ARGS (step->amount));
- break;
- case GST_FORMAT_BUFFERS:
- GST_DEBUG_OBJECT (basesink,
- "got default step %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
- step->remaining, step->amount);
- if (step->remaining > 0) {
- step->remaining--;
- return FALSE;
- }
- break;
- case GST_FORMAT_DEFAULT:
- default:
- GST_DEBUG_OBJECT (basesink,
- "got unknown step %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
- step->remaining, step->amount);
- break;
- }
- GST_DEBUG_OBJECT (basesink, "step complete");
-
- message =
- gst_message_new_step_done (GST_OBJECT_CAST (basesink), step->format,
- step->amount, step->rate, step->duration, step->intermediate);
- gst_message_set_seqnum (message, step->seqnum);
- gst_element_post_message (GST_ELEMENT_CAST (basesink), message);
-
- step->remaining = -1;
- if (!step->intermediate)
- basesink->need_preroll = step->need_preroll;
- }
- return TRUE;
-
-}
-
/* with STREAM_LOCK, PREROLL_LOCK
*
* Make sure we are in PLAYING and synchronize an object to the clock.
gboolean do_sync;
GstBaseSinkPrivate *priv;
GstFlowReturn ret;
- guint step_cookie;
+ GstStepInfo *current, *pending;
+ gboolean stepped;
priv = basesink->priv;
do_step:
sstart = sstop = rstart = rstop = -1;
do_sync = TRUE;
+ stepped = FALSE;
priv->current_rstart = -1;
+ /* get stepping info */
+ current = &priv->current_step;
+ pending = &priv->pending_step;
+
/* get timing information for this object against the render segment */
syncable = gst_base_sink_get_sync_times (basesink, obj,
- &sstart, &sstop, &rstart, &rstop, &do_sync, &basesink->segment);
+ &sstart, &sstop, &rstart, &rstop, &do_sync, &stepped, &basesink->segment,
+ current);
+
+ if (G_UNLIKELY (stepped))
+ goto step_skipped;
/* a syncable object needs to participate in preroll and
* clocking. All buffers and EOS are syncable. */
if (G_UNLIKELY (!syncable))
goto not_syncable;
- /* see if we need to skip this buffer as part of stepping */
- if (!handle_stepping (basesink))
- goto step_skipped;
-
/* store timing info for current object */
priv->current_rstart = rstart;
priv->current_rstop = (rstop != -1 ? rstop : rstart);
/* save sync time for eos when the previous object needed sync */
priv->eos_rtime = (do_sync ? priv->current_rstop : -1);
- step_cookie = priv->step.cookie;
-
again:
/* first do preroll, this makes sure we commit our state
* to PAUSED and can continue to PLAYING. We cannot perform
if (G_UNLIKELY (ret != GST_FLOW_OK))
goto preroll_failed;
- if (step_cookie != priv->step.cookie)
+ /* update the segment with a pending step if the current one is invalid and we
+ * have a new pending one. We only accept new step updates after a preroll */
+ if (G_UNLIKELY (pending->valid && !current->valid)) {
+ start_stepping (basesink, &basesink->segment, pending, current);
goto do_step;
+ }
/* After rendering we store the position of the last buffer so that we can use
* it to report the position. We need to take the lock here. */
step_skipped:
{
GST_DEBUG_OBJECT (basesink, "skipped stepped object %p", obj);
+ *late = TRUE;
return GST_FLOW_OK;
}
not_syncable:
@@ -3282,15 +3350,14 @@ gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event)
bclass->unlock (sink);
GST_PAD_PREROLL_LOCK (sink->sinkpad);
- priv->step.cookie++;
-
/* update the segment */
- priv->step.seqnum = seqnum;
- priv->step.format = format;
- priv->step.amount = amount;
- priv->step.remaining = amount;
- priv->step.rate = rate;
- priv->step.intermediate = intermediate;
+ priv->pending_step.seqnum = seqnum;
+ priv->pending_step.format = format;
+ priv->pending_step.amount = amount;
+ priv->pending_step.remaining = amount;
+ priv->pending_step.rate = rate;
+ priv->pending_step.intermediate = intermediate;
+ priv->pending_step.valid = TRUE;
/* now that we have the PREROLL lock, clear our unlock request */
if (bclass->unlock_stop)
@@ -3300,7 +3367,7 @@ gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event)
/* and we need to commit our state again on the next
* prerolled buffer */
sink->playing_async = TRUE;
- priv->step.need_preroll = TRUE;
+ priv->pending_step.need_preroll = TRUE;
sink->need_preroll = FALSE;
gst_element_lost_state_full (GST_ELEMENT_CAST (sink), FALSE);
} else {
@@ -3315,9 +3382,6 @@ gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event)
gst_clock_id_unschedule (sink->clock_id);
}
- gst_element_post_message (GST_ELEMENT_CAST (sink),
- gst_message_new_async_start (GST_OBJECT_CAST (sink), FALSE));
-
GST_DEBUG_OBJECT (sink, "signal waiter");
GST_PAD_PREROLL_SIGNAL (sink->sinkpad);
gst_base_sink_reset_qos (basesink);
priv->commited = FALSE;
priv->call_preroll = TRUE;
- priv->step.remaining = -1;
+ priv->current_step.valid = FALSE;
+ priv->pending_step.valid = FALSE;
if (priv->async_enabled) {
GST_DEBUG_OBJECT (basesink, "doing async state change");
/* when async enabled, post async-start message and return ASYNC from