segment: add offset field
authorWim Taymans <wim.taymans@collabora.co.uk>
Fri, 27 Jul 2012 15:09:45 +0000 (17:09 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Fri, 27 Jul 2012 15:09:45 +0000 (17:09 +0200)
Add an offset field that is used to track at what position the segment was
updated. This is used to set the running time to 0 when we do a flushing
seek that doesn't update the position.

See https://bugzilla.gnome.org/show_bug.cgi?id=680306

gst/gstsegment.c
gst/gstsegment.h
tests/check/gst/gstsegment.c

index 6ff04fa..0badbca 100644 (file)
@@ -174,6 +174,7 @@ gst_segment_init (GstSegment * segment, GstFormat format)
   segment->applied_rate = 1.0;
   segment->format = format;
   segment->base = 0;
+  segment->offset = 0;
   segment->start = 0;
   segment->stop = -1;
   segment->time = 0;
@@ -308,6 +309,7 @@ gst_segment_do_seek (GstSegment * segment, gdouble rate,
     /* flush resets the running_time */
     base = 0;
   } else {
+    /* remember the elapsed time */
     base = gst_segment_to_running_time (segment, format, position);
   }
 
@@ -324,14 +326,12 @@ gst_segment_do_seek (GstSegment * segment, gdouble rate,
         position = 0;
     }
   }
+
   /* set update arg to reflect update of position */
   if (update)
     *update = position != segment->position;
 
   /* update new values */
-  segment->rate = rate;
-  segment->applied_rate = 1.0;
-  segment->base = base;
   /* be explicit about our GstSeekFlag -> GstSegmentFlag conversion */
   segment->flags = GST_SEGMENT_FLAG_NONE;
   if ((flags & GST_SEEK_FLAG_FLUSH) != 0)
@@ -340,6 +340,22 @@ gst_segment_do_seek (GstSegment * segment, gdouble rate,
     segment->flags |= GST_SEGMENT_FLAG_SKIP;
   if ((flags & GST_SEEK_FLAG_SEGMENT) != 0)
     segment->flags |= GST_SEGMENT_FLAG_SEGMENT;
+
+  segment->rate = rate;
+  segment->applied_rate = 1.0;
+
+  segment->base = base;
+  if (rate > 0.0)
+    segment->offset = position - start;
+  else {
+    if (stop != -1)
+      segment->offset = stop - position;
+    else if (segment->duration != -1)
+      segment->offset = segment->duration - position;
+    else
+      segment->offset = 0;
+  }
+
   segment->start = start;
   segment->stop = stop;
   segment->time = start;
@@ -461,6 +477,9 @@ gst_segment_to_running_time (const GstSegment * segment, GstFormat format,
 
   start = segment->start;
 
+  if (segment->rate > 0.0)
+    start += segment->offset;
+
   /* before the segment boundary */
   if (G_UNLIKELY (position < start))
     return -1;
@@ -477,7 +496,11 @@ gst_segment_to_running_time (const GstSegment * segment, GstFormat format,
   } else {
     /* cannot continue if no stop position set or outside of
      * the segment. */
-    if (G_UNLIKELY (stop == -1 || position > stop))
+    if (G_UNLIKELY (stop == -1))
+      return -1;
+
+    stop -= segment->offset;
+    if (G_UNLIKELY (position > stop))
       return -1;
 
     /* bring to uncorrected position in segment */
index 10c6405..580106b 100644 (file)
@@ -144,7 +144,8 @@ typedef enum {
  * @rate: the rate of the segment
  * @applied_rate: the already applied rate to the segment
  * @format: the format of the segment values
- * @base: the base time of the segment
+ * @base: the base of the segment
+ * @offset: the offset to apply to @start or @stop
  * @start: the start of the segment
  * @stop: the stop of the segment
  * @time: the stream time of the segment
@@ -163,6 +164,7 @@ struct _GstSegment {
 
   GstFormat       format;
   guint64         base;
+  guint64         offset;
   guint64         start;
   guint64         stop;
   guint64         time;
index f498388..98d48c0 100644 (file)
@@ -31,8 +31,8 @@ check_times (GstSegment * segment, guint64 position, guint64 stream_time,
   st = gst_segment_to_stream_time (segment, segment->format, position);
   rt = gst_segment_to_running_time (segment, segment->format, position);
 
-  fail_unless (st == stream_time);
-  fail_unless (rt == running_time);
+  fail_unless_equals_int64 (st, stream_time);
+  fail_unless_equals_int64 (rt, running_time);
 }
 
 /* mess with the segment structure in the bytes format */
@@ -138,8 +138,10 @@ GST_START_TEST (segment_seek_nosize)
   fail_unless (segment.start == 200);
   fail_unless (segment.position == 200);
   fail_unless (segment.stop == 300);
+  fail_unless (segment.base == 50);
   fail_unless (update == TRUE);
   check_times (&segment, 200, 200, 50);
+  check_times (&segment, 250, 250, 100);
 
   update = FALSE;
   /* add 100 to start (to 300), set stop to 200, this is not allowed.
@@ -152,8 +154,10 @@ GST_START_TEST (segment_seek_nosize)
   fail_unless (segment.start == 200);
   fail_unless (segment.position == 200);
   fail_unless (segment.stop == 300);
+  fail_unless (segment.base == 50);
   /* update didn't change */
   fail_unless (update == FALSE);
+  check_times (&segment, 200, 200, 50);
   check_times (&segment, 250, 250, 100);
 
   update = TRUE;
@@ -166,6 +170,7 @@ GST_START_TEST (segment_seek_nosize)
   fail_unless (segment.start == 200);
   fail_unless (segment.position == 200);
   fail_unless (segment.stop == 300);
+  fail_unless (segment.base == 50);
   fail_unless (update == FALSE);
   check_times (&segment, 250, 250, 100);
 
@@ -477,9 +482,11 @@ GST_START_TEST (segment_seek_rate)
       GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_NONE, -1, &update);
   fail_unless (segment.format == GST_FORMAT_BYTES);
   fail_unless (segment.start == 0);
+  fail_unless (segment.position == 0);
   fail_unless (segment.stop == -1);
   fail_unless (segment.rate == 2.0);
   fail_unless (update == FALSE);
+  check_times (&segment, 50, 50, 25);
 
   /* set a real stop position, this must happen in bytes */
   gst_segment_do_seek (&segment, 3.0,
@@ -493,6 +500,7 @@ GST_START_TEST (segment_seek_rate)
   /* no seek should happen, we just updated the stop position in forward
    * playback mode.*/
   fail_unless (update == FALSE);
+  check_times (&segment, 60, 60, 20);
 
   /* set some duration, stop -1 END seeks will now work with the
    * duration, if the formats match */
@@ -549,6 +557,63 @@ GST_START_TEST (segment_copy)
 
 GST_END_TEST;
 
+/* mess with the segment structure in the bytes format */
+GST_START_TEST (segment_seek_noupdate)
+{
+  GstSegment segment;
+  gboolean update;
+
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+
+  segment.start = 0;
+  segment.position = 50;
+  segment.stop = 200;
+  segment.time = 0;
+
+  /* doesn't change anything */
+  gst_segment_do_seek (&segment, 1.0,
+      GST_FORMAT_TIME,
+      GST_SEEK_FLAG_NONE,
+      GST_SEEK_TYPE_NONE, 0, GST_SEEK_TYPE_NONE, 0, &update);
+  fail_unless (update == FALSE);
+  fail_unless (segment.format == GST_FORMAT_TIME);
+  fail_unless (segment.start == 0);
+  fail_unless (segment.stop == 200);
+  fail_unless (segment.time == 0);
+  fail_unless (segment.position == 50);
+  fail_unless (segment.base == 50);
+  fail_unless (segment.offset == 50);
+
+  gst_segment_do_seek (&segment, 2.0,
+      GST_FORMAT_TIME,
+      GST_SEEK_FLAG_NONE,
+      GST_SEEK_TYPE_NONE, 0, GST_SEEK_TYPE_NONE, 0, &update);
+  fail_unless (update == FALSE);
+  fail_unless (segment.format == GST_FORMAT_TIME);
+  fail_unless (segment.start == 0);
+  fail_unless (segment.stop == 200);
+  fail_unless (segment.time == 0);
+  fail_unless (segment.position == 50);
+  fail_unless (segment.base == 50);
+  fail_unless_equals_int (segment.offset, 50);
+
+  gst_segment_do_seek (&segment, 1.0,
+      GST_FORMAT_TIME,
+      GST_SEEK_FLAG_FLUSH,
+      GST_SEEK_TYPE_NONE, 0, GST_SEEK_TYPE_NONE, 0, &update);
+  fail_unless (update == FALSE);
+  fail_unless (segment.format == GST_FORMAT_TIME);
+  fail_unless (segment.start == 0);
+  fail_unless (segment.stop == 200);
+  fail_unless (segment.time == 0);
+  fail_unless (segment.position == 50);
+  fail_unless (segment.base == 0);
+  fail_unless (segment.offset == 50);
+}
+
+GST_END_TEST;
+
+
 static Suite *
 gst_segment_suite (void)
 {
@@ -563,6 +628,7 @@ gst_segment_suite (void)
   tcase_add_test (tc_chain, segment_seek_reverse);
   tcase_add_test (tc_chain, segment_seek_rate);
   tcase_add_test (tc_chain, segment_copy);
+  tcase_add_test (tc_chain, segment_seek_noupdate);
 
   return s;
 }