adder: rework timestamping

Adder was using always incrementing timestamps. Seeking was done by setting the
position in the newsegment event. This was failing when doing segmented seeks
with rate<0.0, as offset (and thus timestamp) would go below 0.

Now we take both cur and end from the seek event. We construct newsegment events
depending including cur and end from the seek event. We set position to the
start of the segment. Timestamp is set to start or end of segment depending on
rate. Offset is recalculated.
This commit is contained in:
Stefan Kost 2010-04-14 23:31:20 +03:00
parent eec0f7c876
commit ab223520ed
2 changed files with 52 additions and 45 deletions

View file

@ -698,13 +698,13 @@ gst_adder_src_event (GstPad * pad, GstEvent * event)
case GST_EVENT_SEEK: case GST_EVENT_SEEK:
{ {
GstSeekFlags flags; GstSeekFlags flags;
GstSeekType curtype; GstSeekType curtype, endtype;
gint64 cur; gint64 cur, end;
gboolean flush; gboolean flush;
/* parse the seek parameters */ /* parse the seek parameters */
gst_event_parse_seek (event, &adder->segment_rate, NULL, &flags, &curtype, gst_event_parse_seek (event, &adder->segment_rate, NULL, &flags, &curtype,
&cur, NULL, NULL); &cur, &endtype, &end);
flush = (flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH; flush = (flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH;
@ -724,9 +724,13 @@ gst_adder_src_event (GstPad * pad, GstEvent * event)
* new collect function will be called for as long as we're flushing. */ * new collect function will be called for as long as we're flushing. */
GST_OBJECT_LOCK (adder->collect); GST_OBJECT_LOCK (adder->collect);
if (curtype == GST_SEEK_TYPE_SET) if (curtype == GST_SEEK_TYPE_SET)
adder->segment_position = cur; adder->segment_start = cur;
else else
adder->segment_position = 0; adder->segment_start = 0;
if (endtype == GST_SEEK_TYPE_SET)
adder->segment_end = end;
else
adder->segment_end = GST_CLOCK_TIME_NONE;
/* make sure we push a new segment, to inform about new basetime /* make sure we push a new segment, to inform about new basetime
* see FIXME in gst_adder_collected() */ * see FIXME in gst_adder_collected() */
adder->segment_pending = TRUE; adder->segment_pending = TRUE;
@ -1071,6 +1075,8 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data)
GstBuffer *outbuf = NULL, *gapbuf = NULL; GstBuffer *outbuf = NULL, *gapbuf = NULL;
gpointer outdata = NULL; gpointer outdata = NULL;
guint outsize; guint outsize;
gint64 next_offset;
gint64 next_timestamp;
adder = GST_ADDER (user_data); adder = GST_ADDER (user_data);
@ -1178,37 +1184,30 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data)
/* we had an output buffer, unref the gapbuffer we kept */ /* we had an output buffer, unref the gapbuffer we kept */
gst_buffer_unref (gapbuf); gst_buffer_unref (gapbuf);
/* our timestamping is very simple, just an ever incrementing
* counter, the new segment time will take care of their respective
* stream time. */
if (adder->segment_pending) { if (adder->segment_pending) {
GstEvent *event; GstEvent *event;
/* FIXME, use rate/applied_rate as set on all sinkpads. /* FIXME, use rate/applied_rate as set on all sinkpads.
* - currently we just set rate as received from last seek-event * - currently we just set rate as received from last seek-event
* We could potentially figure out the duration as well using *
* the current segment positions and the stated stop positions. * When seeking we set the start and stop positions as given in the seek
* Also we just start from stream time 0 which is rather * event. We also adjust offset & timestamp acordingly.
* weird. For non-synchronized mixing, the time should be * This basically ignores all newsegments sent by upstream.
* the min of the stream times of all received segments,
* rationale being that the duration is at least going to
* be as long as the earliest stream we start mixing. This
* would also be correct for synchronized mixing but then
* the later streams would be delayed until the stream times
* match.
*/ */
event = gst_event_new_new_segment_full (FALSE, adder->segment_rate,
1.0, GST_FORMAT_TIME, adder->segment_start, adder->segment_end,
adder->segment_start);
if (adder->segment_rate > 0.0) { if (adder->segment_rate > 0.0) {
event = gst_event_new_new_segment_full (FALSE, adder->segment_rate, adder->timestamp = adder->segment_start;
1.0, GST_FORMAT_TIME, adder->timestamp, GST_CLOCK_TIME_NONE,
adder->segment_position);
} else { } else {
event = gst_event_new_new_segment_full (FALSE, adder->segment_rate, adder->timestamp = adder->segment_end;
1.0, GST_FORMAT_TIME, G_GINT64_CONSTANT (0), adder->timestamp,
adder->segment_position);
} }
GST_INFO_OBJECT (adder->srcpad, "new segment event for " adder->offset = gst_util_uint64_scale (adder->timestamp,
"rate:%lf start:%" G_GINT64_FORMAT " cur:%" G_GUINT64_FORMAT, adder->rate, GST_SECOND);
adder->segment_rate, adder->timestamp, adder->segment_position); GST_INFO_OBJECT (adder, "seg_start %" G_GUINT64_FORMAT ", seg_end %"
G_GUINT64_FORMAT, adder->segment_start, adder->segment_end);
GST_INFO_OBJECT (adder, "timestamp %" G_GINT64_FORMAT ",new offset %"
G_GINT64_FORMAT, adder->timestamp, adder->offset);
if (event) { if (event) {
if (!gst_pad_push_event (adder->srcpad, event)) { if (!gst_pad_push_event (adder->srcpad, event)) {
@ -1216,11 +1215,10 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data)
event, GST_EVENT_TYPE_NAME (event)); event, GST_EVENT_TYPE_NAME (event));
} }
adder->segment_pending = FALSE; adder->segment_pending = FALSE;
adder->segment_position = 0;
} else { } else {
GST_WARNING_OBJECT (adder->srcpad, "Creating new segment event for " GST_WARNING_OBJECT (adder->srcpad, "Creating new segment event for "
"start:%" G_GINT64_FORMAT " pos:%" G_GUINT64_FORMAT " failed", "start:%" G_GINT64_FORMAT " end:%" G_GINT64_FORMAT " failed",
adder->timestamp, adder->segment_position); adder->segment_start, adder->segment_end);
} }
} }
@ -1237,27 +1235,35 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data)
adder->pending_events = NULL; adder->pending_events = NULL;
} }
/* set timestamps on the output buffer */
GST_BUFFER_TIMESTAMP (outbuf) = adder->timestamp;
GST_BUFFER_OFFSET (outbuf) = adder->offset;
/* for the next timestamp, use the sample counter, which will /* for the next timestamp, use the sample counter, which will
* never accumulate rounding errors */ * never accumulate rounding errors */
if (adder->segment_rate > 0.0) { if (adder->segment_rate > 0.0) {
adder->offset += outsize / adder->bps; next_offset = adder->offset + outsize / adder->bps;
} else { } else {
adder->offset -= outsize / adder->bps; next_offset = adder->offset - outsize / adder->bps;
} }
adder->timestamp = gst_util_uint64_scale_int (adder->offset, next_timestamp = gst_util_uint64_scale (next_offset, GST_SECOND, adder->rate);
GST_SECOND, adder->rate);
/* now we can set the duration of the buffer */
GST_BUFFER_DURATION (outbuf) = adder->timestamp - /* set timestamps on the output buffer */
GST_BUFFER_TIMESTAMP (outbuf); if (adder->segment_rate > 0.0) {
GST_BUFFER_TIMESTAMP (outbuf) = adder->timestamp;
GST_BUFFER_OFFSET (outbuf) = adder->offset;
GST_BUFFER_DURATION (outbuf) = next_timestamp - adder->timestamp;
} else {
GST_BUFFER_TIMESTAMP (outbuf) = next_timestamp;
GST_BUFFER_OFFSET (outbuf) = next_offset;
GST_BUFFER_DURATION (outbuf) = adder->timestamp - next_timestamp;
}
adder->offset = next_offset;
adder->timestamp = next_timestamp;
/* send it out */ /* send it out */
GST_LOG_OBJECT (adder, "pushing outbuf %p, timestamp %" GST_TIME_FORMAT, GST_LOG_OBJECT (adder, "pushing outbuf %p, timestamp %" GST_TIME_FORMAT
outbuf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); " offset %" G_GINT64_FORMAT, outbuf,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
GST_BUFFER_OFFSET (outbuf));
ret = gst_pad_push (adder->srcpad, outbuf); ret = gst_pad_push (adder->srcpad, outbuf);
GST_LOG_OBJECT (adder, "pushed outbuf, result = %s", gst_flow_get_name (ret)); GST_LOG_OBJECT (adder, "pushed outbuf, result = %s", gst_flow_get_name (ret));
@ -1295,7 +1301,8 @@ gst_adder_change_state (GstElement * element, GstStateChange transition)
adder->offset = 0; adder->offset = 0;
adder->flush_stop_pending = FALSE; adder->flush_stop_pending = FALSE;
adder->segment_pending = TRUE; adder->segment_pending = TRUE;
adder->segment_position = 0; adder->segment_start = 0;
adder->segment_end = GST_CLOCK_TIME_NONE;
adder->segment_rate = 1.0; adder->segment_rate = 1.0;
gst_segment_init (&adder->segment, GST_FORMAT_UNDEFINED); gst_segment_init (&adder->segment, GST_FORMAT_UNDEFINED);
gst_collect_pads_start (adder->collect); gst_collect_pads_start (adder->collect);

View file

@ -85,7 +85,7 @@ struct _GstAdder {
GstPadEventFunction collect_event; GstPadEventFunction collect_event;
GstSegment segment; GstSegment segment;
gboolean segment_pending; gboolean segment_pending;
guint64 segment_position; guint64 segment_start, segment_end;
gdouble segment_rate; gdouble segment_rate;
/* src event handling */ /* src event handling */
gboolean flush_stop_pending; gboolean flush_stop_pending;