segment: Add _full variants of all stream/running_time from/to segment position functions
authorVivia Nikolaidou <vivia@ahiru.eu>
Thu, 15 Oct 2015 11:49:37 +0000 (14:49 +0300)
committerSebastian Dröge <sebastian@centricular.com>
Fri, 23 Oct 2015 12:50:38 +0000 (15:50 +0300)
See formula clarifications in design docs for calculation details.

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

docs/design/part-synchronisation.txt
docs/gst/gstreamer-sections.txt
gst/gstsegment.c
gst/gstsegment.h
tests/check/gst/gstsegment.c
win32/common/libgstreamer.def

index 3c0dcd1..cac9f07 100644 (file)
@@ -101,8 +101,13 @@ The following transformation to running_time exist:
 
   if (S.rate > 0.0)
     B.running_time = (B.timestamp - (S.start + S.offset)) / ABS (S.rate) + S.base
+    =>
+    B.timestamp = (B.running_time - S.base) * ABS (S.rate) + S.start + S.offset
   else
     B.running_time = ((S.stop - S.offset) - B.timestamp) / ABS (S.rate) + S.base
+    =>
+    B.timestamp = S.stop - S.offset - ((B.running_time - S.base) * ABS (S.rate))
+
 
 We write B.running_time as the running_time obtained from the SEGMENT event
 and the buffers of that segment.
@@ -191,9 +196,13 @@ Stream time is calculated using the buffer times and the preceding SEGMENT
 event as follows:
 
     stream_time = (B.timestamp - S.start) * ABS (S.applied_rate) + S.time
+    => B.timestamp = (stream_time - S.time) / ABS(S.applied_rate) + S.start
+
 For negative rates, B.timestamp will go backwards from S.stop to S.start,
-making the stream time go backwards.
+making the stream time go backwards:
+
+    stream_time = (S.stop - B.timestamp) * ABS(S.applied_rate) + S.time
+    => B.timestamp = S.stop - (stream_time - S.time) / ABS(S.applied_rate)
 
 In the PLAYING state, it is also possible to use the pipeline clock to derive
 the current stream_time.
index 5f5e577..512d579 100644 (file)
@@ -2569,10 +2569,13 @@ gst_segment_copy
 gst_segment_free
 gst_segment_do_seek
 gst_segment_position_from_stream_time
+gst_segment_position_from_stream_time_full
 gst_segment_to_running_time
 gst_segment_to_running_time_full
 gst_segment_to_stream_time
+gst_segment_to_stream_time_full
 gst_segment_position_from_running_time
+gst_segment_position_from_running_time_full
 gst_segment_to_position
 gst_segment_set_running_time
 gst_segment_copy_into
index 2307ded..b7c31f2 100644 (file)
@@ -375,6 +375,114 @@ gst_segment_do_seek (GstSegment * segment, gdouble rate,
 }
 
 /**
+ * gst_segment_to_stream_time_full:
+ * @segment: a #GstSegment structure.
+ * @format: the format of the segment.
+ * @position: the position in the segment
+ * @stream_time: result stream-time
+ *
+ * Translate @position to the total stream time using the currently configured
+ * segment. Compared to gst_segment_to_stream_time() this function can return
+ * negative stream-time.
+ *
+ * This function is typically used by elements that need to synchronize buffers
+ * against the clock or eachother.
+ *
+ * @position can be any value and the result of this function for values outside
+ * of the segment is extrapolated.
+ *
+ * When 1 is returned, @position resulted in a positive stream-time returned
+ * in @stream_time.
+ *
+ * When this function returns -1, the returned @stream_time should be negated
+ * to get the real negative stream time.
+ *
+ * Returns: a 1 or -1 on success, 0 on failure.
+ *
+ * Since: 1.8
+ */
+gint
+gst_segment_to_stream_time_full (const GstSegment * segment, GstFormat format,
+    guint64 position, guint64 * stream_time)
+{
+  guint64 start, stop, time;
+  gdouble abs_applied_rate;
+  gint res;
+
+  /* format does not matter for -1 */
+  if (G_UNLIKELY (position == -1)) {
+    *stream_time = -1;
+    return 0;
+  }
+
+  g_return_val_if_fail (segment != NULL, 0);
+  g_return_val_if_fail (segment->format == format, 0);
+
+  stop = segment->stop;
+
+  start = segment->start;
+  time = segment->time;
+
+  /* time must be known */
+  if (G_UNLIKELY (time == -1))
+    return 0;
+
+  abs_applied_rate = ABS (segment->applied_rate);
+
+  /* add or subtract from segment time based on applied rate */
+  if (G_LIKELY (segment->applied_rate > 0.0)) {
+    if (G_LIKELY (position > start)) {
+      /* bring to uncorrected position in segment */
+      *stream_time = position - start;
+      /* correct for applied rate if needed */
+      if (G_UNLIKELY (abs_applied_rate != 1.0))
+        *stream_time *= abs_applied_rate;
+      /* correct for segment time */
+      *stream_time += time;
+      res = 1;
+    } else {
+      *stream_time = start - position;
+      if (G_UNLIKELY (abs_applied_rate != 1.0))
+        *stream_time *= abs_applied_rate;
+      if (*stream_time > time) {
+        *stream_time -= time;
+        res = -1;
+      } else {
+        *stream_time = time - *stream_time;
+        res = 1;
+      }
+    }
+  } else {
+    /* correct for segment time. Streams with a negative applied_rate
+     * have timestamps between start and stop, as usual, but have the
+     * time member starting high and going backwards.  */
+    /* cannot continue without a known segment stop */
+    if (G_UNLIKELY (stop == -1))
+      return 0;
+    if (G_UNLIKELY (position > stop)) {
+      *stream_time = position - stop;
+      if (G_UNLIKELY (abs_applied_rate != 1.0))
+        *stream_time *= abs_applied_rate;
+      if (*stream_time > time) {
+        *stream_time -= time;
+        res = -1;
+      } else {
+        *stream_time = time - *stream_time;
+        res = 1;
+      }
+    } else {
+      *stream_time = stop - position;
+      if (G_UNLIKELY (abs_applied_rate != 1.0))
+        *stream_time *= abs_applied_rate;
+      *stream_time += time;
+      res = 1;
+    }
+  }
+
+  return res;
+}
+
+/**
  * gst_segment_to_stream_time:
  * @segment: a #GstSegment structure.
  * @format: the format of the segment.
@@ -393,65 +501,146 @@ gst_segment_do_seek (GstSegment * segment, gdouble rate,
  *
  * Returns: the position in stream_time or -1 when an invalid position
  * was given.
+ *
+ * Since: 1.8
  */
 guint64
 gst_segment_to_stream_time (const GstSegment * segment, GstFormat format,
     guint64 position)
 {
-  guint64 stream_time, start, stop, time;
-  gdouble abs_applied_rate;
-
-  /* format does not matter for -1 */
-  if (G_UNLIKELY (position == -1))
-    return -1;
+  guint64 result;
 
   g_return_val_if_fail (segment != NULL, -1);
   g_return_val_if_fail (segment->format == format, -1);
 
-  stop = segment->stop;
-
-  /* outside of the segment boundary stop */
-  if (G_UNLIKELY (stop != -1 && position > stop))
+  /* before the segment boundary */
+  if (G_UNLIKELY (position < segment->start)) {
+    GST_DEBUG ("position(%" G_GUINT64_FORMAT ") < start(%" G_GUINT64_FORMAT
+        ")", position, segment->start);
+    return -1;
+  }
+  /* after the segment boundary */
+  if (G_UNLIKELY (segment->stop != -1 && position > segment->stop)) {
+    GST_DEBUG ("position(%" G_GUINT64_FORMAT ") > stop(%" G_GUINT64_FORMAT
+        ")", position, segment->stop);
     return -1;
+  }
 
-  start = segment->start;
+  if (gst_segment_to_stream_time_full (segment, format, position, &result) == 1)
+    return result;
 
-  /* before the segment boundary */
-  if (G_UNLIKELY (position < start))
-    return -1;
+  return 0;
+}
+
+/**
+ * gst_segment_position_from_stream_time_full:
+ * @segment: a #GstSegment structure.
+ * @format: the format of the segment.
+ * @stream_time: the stream-time
+ * @position: the resulting position in the segment
+ *
+ * Translate @stream_time to the segment position using the currently configured
+ * segment. Compared to gst_segment_position_from_stream_time() this function can
+ * return negative segment position.
+ *
+ * This function is typically used by elements that need to synchronize buffers
+ * against the clock or each other.
+ *
+ * @stream_time can be any value and the result of this function for values outside
+ * of the segment is extrapolated.
+ *
+ * When 1 is returned, @stream_time resulted in a positive position returned
+ * in @position.
+ *
+ * When this function returns -1, the returned @position should be negated
+ * to get the real negative segment position.
+ *
+ * Returns: a 1 or -1 on success, 0 on failure.
+ *
+ * Since: 1.8
+ */
+gint
+gst_segment_position_from_stream_time_full (const GstSegment * segment,
+    GstFormat format, guint64 stream_time, guint64 * position)
+{
+  guint64 start, time;
+  gdouble abs_applied_rate;
+  gint res;
 
+  /* format does not matter for -1 */
+  if (G_UNLIKELY (stream_time == -1)) {
+    *position = -1;
+    return 0;
+  }
+
+  g_return_val_if_fail (segment != NULL, -1);
+  g_return_val_if_fail (segment->format == format, -1);
+
+  start = segment->start;
   time = segment->time;
 
   /* time must be known */
   if (G_UNLIKELY (time == -1))
-    return -1;
+    return 0;
 
   abs_applied_rate = ABS (segment->applied_rate);
 
-  /* add or subtract from segment time based on applied rate */
   if (G_LIKELY (segment->applied_rate > 0.0)) {
-    if (G_UNLIKELY (position < start))
-      return -1;
-    /* bring to uncorrected position in segment */
-    stream_time = position - start;
+    if (G_LIKELY (stream_time > time)) {
+      res = 1;
+      *position = stream_time - time;
+    } else {
+      res = -1;
+      *position = time - stream_time;
+    }
     /* correct for applied rate if needed */
     if (G_UNLIKELY (abs_applied_rate != 1.0))
-      stream_time *= abs_applied_rate;
-    /* correct for segment time */
-    stream_time += time;
+      *position /= abs_applied_rate;
+
+    if (G_UNLIKELY (res == -1)) {
+      if (*position > start) {
+        *position -= start;
+      } else {
+        *position = start - *position;
+        res = 1;
+      }
+    } else {
+      *position += start;
+    }
   } else {
-    /* correct for segment time, clamp at 0. Streams with a negative
-     * applied_rate have timestamps between start and stop, as usual, but have
-     * the time member starting high and going backwards.  */
-    if (G_UNLIKELY (position > stop))
-      return -1;
-    stream_time = stop - position;
+    GstClockTime stop = segment->stop;
+    /* cannot continue without a known segment stop */
+    if (G_UNLIKELY (stop == -1))
+      return 0;
+    if (G_UNLIKELY (time > stream_time)) {
+      res = -1;
+      *position = time - stream_time;
+    } else {
+      res = 1;
+      *position = stream_time - time;
+    }
     if (G_UNLIKELY (abs_applied_rate != 1.0))
-      stream_time *= abs_applied_rate;
-    stream_time += time;
+      *position /= abs_applied_rate;
+    if (G_UNLIKELY (stop < *position)) {
+      if (G_LIKELY (res == 1)) {
+        *position -= stop;
+        res = -1;
+      } else {
+        *position += stop;
+        res = 1;
+      }
+    } else {
+      if (G_LIKELY (res == 1)) {
+        *position = stop - *position;
+        res = 1;
+      } else {
+        *position += stop;
+        res = 1;
+      }
+    }
   }
 
-  return stream_time;
+  return res;
 }
 
 /**
@@ -472,56 +661,34 @@ guint64
 gst_segment_position_from_stream_time (const GstSegment * segment,
     GstFormat format, guint64 stream_time)
 {
-  guint64 position, start, stop, time;
-  gdouble abs_applied_rate;
-
-  /* format does not matter for -1 */
-  if (G_UNLIKELY (stream_time == -1))
-    return -1;
+  guint64 position;
+  gint res;
 
   g_return_val_if_fail (segment != NULL, -1);
   g_return_val_if_fail (segment->format == format, -1);
 
-  start = segment->start;
-  time = segment->time;
-  /* this stream time was for a previous segment */
-  if (G_UNLIKELY (stream_time < segment->time))
-    return -1;
+  res =
+      gst_segment_position_from_stream_time_full (segment, format, stream_time,
+      &position);
 
-  /* time must be known */
-  if (G_UNLIKELY (time == -1))
+  /* before the segment boundary */
+  if (G_UNLIKELY (position < segment->start)) {
+    GST_DEBUG ("position(%" G_GUINT64_FORMAT ") < start(%" G_GUINT64_FORMAT
+        ")", position, segment->start);
     return -1;
+  }
 
-  position = stream_time - time;
-
-  abs_applied_rate = ABS (segment->applied_rate);
-  stop = segment->stop;
-
-  /* correct for applied rate if needed */
-  if (G_UNLIKELY (abs_applied_rate != 1.0))
-    position /= abs_applied_rate;
-
-  if (G_LIKELY (segment->applied_rate > 0.0)) {
-    position += start;
-    /* outside of the segment boundary stop */
-    if (G_UNLIKELY (stop != -1 && position > stop))
-      return -1;
-  } else {
-    /* cannot calculate without known boundary stop */
-    if (G_UNLIKELY (stop == -1))
-      return -1;
-    /* outside segment boundary */
-    if (G_UNLIKELY (position > stop))
-      return -1;
-
-    position = stop - position;
-
-    /* position before segment start */
-    if (G_UNLIKELY (position < start))
-      return -1;
+  /* after the segment boundary */
+  if (G_UNLIKELY (segment->stop != -1 && position > segment->stop)) {
+    GST_DEBUG ("position(%" G_GUINT64_FORMAT ") > stop(%" G_GUINT64_FORMAT
+        ")", position, segment->stop);
+    return -1;
   }
 
-  return position;
+  if (res == 1)
+    return position;
+
+  return -1;
 }
 
 /**
@@ -766,50 +933,139 @@ guint64
 gst_segment_position_from_running_time (const GstSegment * segment,
     GstFormat format, guint64 running_time)
 {
-  guint64 result;
-  guint64 start, stop, base;
-  gdouble abs_rate;
-
-  if (G_UNLIKELY (running_time == -1))
-    return -1;
+  guint64 position;
+  gint res;
 
   g_return_val_if_fail (segment != NULL, -1);
-  g_return_val_if_fail (segment->format == format, FALSE);
+  g_return_val_if_fail (segment->format == format, -1);
 
-  base = segment->base;
+  res =
+      gst_segment_position_from_running_time_full (segment, format,
+      running_time, &position);
 
-  /* this running_time was for a previous segment */
-  if (running_time < base)
+  if (res != 1) {
+    g_print
+        ("here with start %lu stop %lu base %lu rate %f offset %lu running_time %lu position %lu\n",
+        segment->start, segment->stop, segment->base, segment->rate,
+        segment->offset, running_time, position);
     return -1;
+  }
+
+  /* before the segment boundary */
+  if (G_UNLIKELY (position < segment->start)) {
+    GST_DEBUG ("position(%" G_GUINT64_FORMAT ") < start(%" G_GUINT64_FORMAT
+        ")", position, segment->start);
+    return -1;
+  }
+
+  /* after the segment boundary */
+  if (G_UNLIKELY (segment->stop != -1 && position > segment->stop)) {
+    GST_DEBUG ("position(%" G_GUINT64_FORMAT ") > stop(%" G_GUINT64_FORMAT
+        ")", position, segment->stop);
+    return -1;
+  }
 
-  /* start by subtracting the base time */
-  result = running_time - base;
+  return position;
+}
+
+/**
+ * gst_segment_position_from_running_time_full:
+ * @segment: a #GstSegment structure.
+ * @format: the format of the segment.
+ * @running_time: the running-time
+ * @position: the resulting position in the segment
+ *
+ * Translate @running_time to the segment position using the currently configured
+ * segment. Compared to gst_segment_position_from_running_time() this function can
+ * return negative segment position.
+ *
+ * This function is typically used by elements that need to synchronize buffers
+ * against the clock or each other.
+ *
+ * @running_time can be any value and the result of this function for values
+ * outside of the segment is extrapolated.
+ *
+ * When 1 is returned, @running_time resulted in a positive position returned
+ * in @position.
+ *
+ * When this function returns -1, the returned @position should be negated
+ * to get the real negative segment position.
+ *
+ * Returns: a 1 or -1 on success, 0 on failure.
+ *
+ * Since: 1.8
+ */
+gint
+gst_segment_position_from_running_time_full (const GstSegment * segment,
+    GstFormat format, guint64 running_time, guint64 * position)
+{
+  gint res;
+  guint64 start, stop, base;
+  gdouble abs_rate;
+
+  if (G_UNLIKELY (running_time == -1)) {
+    *position = -1;
+    return 0;
+  }
+
+  g_return_val_if_fail (segment != NULL, 0);
+  g_return_val_if_fail (segment->format == format, 0);
+
+  base = segment->base;
 
-  /* move into the segment at the right rate */
   abs_rate = ABS (segment->rate);
-  if (G_UNLIKELY (abs_rate != 1.0))
-    result = ceil (result * abs_rate);
 
   start = segment->start;
   stop = segment->stop;
 
   if (G_LIKELY (segment->rate > 0.0)) {
-    /* bring to corrected position in segment */
-    result += start + segment->offset;
-
-    /* outside of the segment boundary stop */
-    if (G_UNLIKELY (stop != -1 && result > stop))
-      return -1;
+    /* start by subtracting the base time */
+    if (G_LIKELY (running_time >= base)) {
+      *position = running_time - base;
+      /* move into the segment at the right rate */
+      if (G_UNLIKELY (abs_rate != 1.0))
+        *position = ceil (*position * abs_rate);
+      /* bring to corrected position in segment */
+      *position += start + segment->offset;
+      res = 1;
+    } else {
+      *position = base - running_time;
+      if (G_UNLIKELY (abs_rate != 1.0))
+        *position = ceil (*position * abs_rate);
+      if (start + segment->offset > *position) {
+        *position -= start + segment->offset;
+        res = -1;
+      } else {
+        *position = start + segment->offset - *position;
+        res = 1;
+      }
+    }
   } else {
-    /* cannot continue if no stop position set or outside of
-     * the segment. */
-    if (G_UNLIKELY (stop == -1 || result + start > stop))
-      return -1;
-
-    /* bring to corrected position in segment */
-    result = stop - result - segment->offset;
+    if (G_LIKELY (running_time >= base)) {
+      *position = running_time - base;
+      if (G_UNLIKELY (abs_rate != 1.0))
+        *position = ceil (*position * abs_rate);
+      if (G_UNLIKELY (stop < *position + segment->offset)) {
+        *position += segment->offset - stop;
+        res = -1;
+      } else {
+        *position = stop - *position - segment->offset;
+        res = 1;
+      }
+    } else {
+      *position = base - running_time;
+      if (G_UNLIKELY (abs_rate != 1.0))
+        *position = ceil (*position * abs_rate);
+      if (G_UNLIKELY (stop < segment->offset - *position)) {
+        *position -= segment->offset - stop;
+        res = -1;
+      } else {
+        *position = stop + *position - segment->offset;
+        res = 1;
+      }
+    }
   }
-  return result;
+  return res;
 }
 
 /**
index 6c4634a..5487123 100644 (file)
@@ -218,7 +218,9 @@ void         gst_segment_free                (GstSegment *segment);
 
 void         gst_segment_init                (GstSegment *segment, GstFormat format);
 
+gint         gst_segment_to_stream_time_full (const GstSegment *segment, GstFormat format, guint64 position, guint64 * stream_time);
 guint64      gst_segment_to_stream_time      (const GstSegment *segment, GstFormat format, guint64 position);
+gint         gst_segment_position_from_stream_time_full (const GstSegment * segment, GstFormat format, guint64 stream_time, guint64 * position);
 guint64      gst_segment_position_from_stream_time (const GstSegment * segment, GstFormat format, guint64 stream_time);
 guint64      gst_segment_to_running_time     (const GstSegment *segment, GstFormat format, guint64 position);
 
@@ -227,6 +229,7 @@ gint         gst_segment_to_running_time_full (const GstSegment *segment, GstFor
 #ifndef GST_DISABLE_DEPRECATED
 guint64      gst_segment_to_position         (const GstSegment *segment, GstFormat format, guint64 running_time);
 #endif
+gint         gst_segment_position_from_running_time_full (const GstSegment *segment, GstFormat format, guint64 running_time, guint64 * position);
 guint64      gst_segment_position_from_running_time (const GstSegment *segment, GstFormat format, guint64 running_time);
 
 gboolean     gst_segment_set_running_time    (GstSegment *segment, GstFormat format, guint64 running_time);
index 78e0688..f3433e8 100644 (file)
@@ -755,7 +755,7 @@ GST_END_TEST;
 GST_START_TEST (segment_full)
 {
   GstSegment segment;
-  guint64 rt;
+  guint64 rt, pos;
 
   gst_segment_init (&segment, GST_FORMAT_TIME);
 
@@ -770,9 +770,15 @@ GST_START_TEST (segment_full)
   fail_unless (gst_segment_to_running_time_full (&segment, GST_FORMAT_TIME,
           50, &rt) == 1);
   fail_unless (rt == 0);
+  fail_unless (gst_segment_position_from_running_time_full (&segment,
+          GST_FORMAT_TIME, rt, &pos) == 1);
+  fail_unless (pos == 50);
   fail_unless (gst_segment_to_running_time_full (&segment, GST_FORMAT_TIME,
           200, &rt) == 1);
   fail_unless (rt == 150);
+  fail_unless (gst_segment_position_from_running_time_full (&segment,
+          GST_FORMAT_TIME, rt, &pos) == 1);
+  fail_unless (pos == 200);
   fail_unless (!gst_segment_clip (&segment, GST_FORMAT_TIME, 40, 40, NULL,
           NULL));
   fail_unless (gst_segment_to_running_time_full (&segment, GST_FORMAT_TIME, 40,
@@ -785,6 +791,9 @@ GST_START_TEST (segment_full)
           NULL));
   fail_unless (gst_segment_to_running_time_full (&segment, GST_FORMAT_TIME, 201,
           &rt) == 1);
+  fail_unless (gst_segment_position_from_running_time_full (&segment,
+          GST_FORMAT_TIME, rt, &pos) == 1);
+  fail_unless (pos == 201);
 
   fail_unless (gst_segment_offset_running_time (&segment, GST_FORMAT_TIME,
           -50) == TRUE);
@@ -794,6 +803,99 @@ GST_START_TEST (segment_full)
           50, &rt) == -1);
   GST_DEBUG ("%" G_GUINT64_FORMAT, rt);
   fail_unless (rt == 50);
+
+  segment.start = 50;
+  segment.stop = 300;
+  segment.position = 150;
+  segment.time = 0;
+  segment.offset = 0;
+  gst_segment_set_running_time (&segment, GST_FORMAT_TIME, 100);
+  fail_unless_equals_int (segment.base, 100);
+  fail_unless (gst_segment_position_from_running_time_full (&segment,
+          GST_FORMAT_TIME, 70, &pos) == -1);
+  fail_unless (gst_segment_position_from_running_time_full (&segment,
+          GST_FORMAT_TIME, 140, &pos) == 1);
+  fail_unless_equals_int (pos, 190);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (segment_stream_time_full)
+{
+  GstSegment segment;
+  guint64 st, pos;
+
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+
+  segment.start = 50;
+  segment.stop = 200;
+  segment.time = 30;
+  segment.position = 0;
+
+  fail_unless (gst_segment_to_stream_time_full (&segment, GST_FORMAT_TIME,
+          0, &st) == -1);
+  fail_unless_equals_int (st, 20);
+  fail_unless (gst_segment_to_stream_time_full (&segment, GST_FORMAT_TIME,
+          20, &st) == 1);
+  fail_unless_equals_int (st, 0);
+  fail_unless (gst_segment_position_from_stream_time_full (&segment,
+          GST_FORMAT_TIME, 0, &pos) == 1);
+  fail_unless_equals_int (pos, 20);
+  fail_unless (gst_segment_to_stream_time_full (&segment, GST_FORMAT_TIME,
+          10, &st) == -1);
+  fail_unless_equals_int (st, 10);
+  fail_unless (gst_segment_to_stream_time_full (&segment, GST_FORMAT_TIME,
+          40, &st) == 1);
+  fail_unless_equals_int (st, 20);
+  fail_unless (gst_segment_position_from_stream_time_full (&segment,
+          GST_FORMAT_TIME, st, &pos) == 1);
+  fail_unless_equals_int (pos, 40);
+  segment.time = 100;
+  fail_unless (gst_segment_position_from_stream_time_full (&segment,
+          GST_FORMAT_TIME, 40, &pos) == -1);
+  fail_unless_equals_int (pos, 10);
+  fail_unless (gst_segment_position_from_stream_time_full (&segment,
+          GST_FORMAT_TIME, 60, &pos) == 1);
+  fail_unless_equals_int (pos, 10);
+
+  segment.start = 50;
+  segment.position = 150;
+  segment.stop = 200;
+  segment.time = 0;
+  segment.applied_rate = -1;
+  segment.rate = -1;
+
+  fail_unless (gst_segment_to_stream_time_full (&segment, GST_FORMAT_TIME,
+          0, &st) == 1);
+  fail_unless_equals_int (st, 200);
+  fail_unless (gst_segment_position_from_stream_time_full (&segment,
+          GST_FORMAT_TIME, 200, &pos) == 1);
+  fail_unless_equals_int (pos, 0);
+  fail_unless (gst_segment_to_stream_time_full (&segment, GST_FORMAT_TIME,
+          250, &st) == -1);
+  fail_unless_equals_int (st, 50);
+  fail_unless (gst_segment_position_from_stream_time_full (&segment,
+          GST_FORMAT_TIME, 200, &pos) == 1);
+  fail_unless_equals_int (pos, 0);
+  fail_unless (gst_segment_position_from_stream_time_full (&segment,
+          GST_FORMAT_TIME, 250, &pos) == -1);
+  fail_unless_equals_int (pos, 50);
+
+  segment.time = 70;
+  fail_unless (gst_segment_to_stream_time_full (&segment, GST_FORMAT_TIME,
+          250, &st) == 1);
+  fail_unless_equals_int (st, 20);
+  fail_unless (gst_segment_position_from_stream_time_full (&segment,
+          GST_FORMAT_TIME, 50, &pos) == 1);
+  fail_unless_equals_int (pos, 220);
+  fail_unless (gst_segment_position_from_stream_time_full (&segment,
+          GST_FORMAT_TIME, 90, &pos) == 1);
+  fail_unless_equals_int (pos, 180);
+
+  segment.stop = 60;
+  fail_unless (gst_segment_position_from_stream_time_full (&segment,
+          GST_FORMAT_TIME, 5, &pos) == 1);
+  fail_unless_equals_int (pos, 125);
 }
 
 GST_END_TEST;
@@ -897,6 +999,7 @@ gst_segment_suite (void)
   tcase_add_test (tc_chain, segment_full);
   tcase_add_test (tc_chain, segment_negative_rate);
   tcase_add_test (tc_chain, segment_negative_applied_rate);
+  tcase_add_test (tc_chain, segment_stream_time_full);
 
   return s;
 }
index f21679b..10dad7a 100644 (file)
@@ -1158,12 +1158,15 @@ EXPORTS
        gst_segment_new
        gst_segment_offset_running_time
        gst_segment_position_from_running_time
+       gst_segment_position_from_running_time_full
        gst_segment_position_from_stream_time
+       gst_segment_position_from_stream_time_full
        gst_segment_set_running_time
        gst_segment_to_position
        gst_segment_to_running_time
        gst_segment_to_running_time_full
        gst_segment_to_stream_time
+       gst_segment_to_stream_time_full
        gst_segtrap_is_enabled
        gst_segtrap_set_enabled
        gst_state_change_get_type