segment: add method for converting to position
authorWim Taymans <wim.taymans@collabora.co.uk>
Wed, 3 Jun 2009 17:06:30 +0000 (19:06 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Wed, 3 Jun 2009 17:06:30 +0000 (19:06 +0200)
Add gst_segment_to_position() that converts a running_time to a position in the
segment. A faulty variant of this function is currently used in inputselector
but we'll need it for frame stepping too.

API: GstSegment::gst_segment_to_position()

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

index bd2abd0..790b0b9 100644 (file)
@@ -1983,6 +1983,7 @@ gst_segment_set_newsegment_full
 gst_segment_set_seek
 gst_segment_to_running_time
 gst_segment_to_stream_time
+gst_segment_to_position
 <SUBSECTION Standard>
 GST_TYPE_SEGMENT
 gst_segment_get_type
index e1014d9..88601bf 100644 (file)
@@ -465,7 +465,7 @@ gst_segment_set_newsegment_full (GstSegment * segment, gboolean update,
   g_return_if_fail (segment->format == format);
 
   if (update) {
-    if (segment->rate > 0.0) {
+    if (G_LIKELY (segment->rate > 0.0)) {
       /* an update to the current segment is done, elapsed time is
        * difference between the old start and new start. */
       if (start > segment->start)
@@ -511,7 +511,7 @@ gst_segment_set_newsegment_full (GstSegment * segment, gboolean update,
       last_stop = stop;
   }
   /* use previous rate to calculate duration */
-  if (segment->abs_rate != 1.0)
+  if (G_LIKELY (segment->abs_rate != 1.0))
     duration /= segment->abs_rate;
 
   /* accumulate duration */
@@ -565,7 +565,7 @@ gst_segment_to_stream_time (GstSegment * segment, GstFormat format,
 
   /* if we have the position for the same format as the segment, we can compare
    * the start and stop values, otherwise we assume 0 and -1 */
-  if (segment->format == format) {
+  if (G_LIKELY (segment->format == format)) {
     start = segment->start;
     stop = segment->stop;
     time = segment->time;
@@ -593,18 +593,18 @@ gst_segment_to_stream_time (GstSegment * segment, GstFormat format,
   abs_applied_rate = ABS (segment->applied_rate);
 
   /* correct for applied rate if needed */
-  if (abs_applied_rate != 1.0)
+  if (G_UNLIKELY (abs_applied_rate != 1.0))
     result *= abs_applied_rate;
 
   /* add or subtract from segment time based on applied rate */
-  if (segment->applied_rate > 0.0) {
+  if (G_LIKELY (segment->applied_rate > 0.0)) {
     /* correct for segment time */
     result += time;
   } 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 (time > result)
+    if (G_LIKELY (time > result))
       result = time - result;
     else
       result = 0;
@@ -650,7 +650,7 @@ gst_segment_to_running_time (GstSegment * segment, GstFormat format,
 
   /* if we have the position for the same format as the segment, we can compare
    * the start and stop values, otherwise we assume 0 and -1 */
-  if (segment->format == format) {
+  if (G_LIKELY (segment->format == format)) {
     start = segment->start;
     stop = segment->stop;
     accum = segment->accum;
@@ -664,7 +664,7 @@ gst_segment_to_running_time (GstSegment * segment, GstFormat format,
   if (G_UNLIKELY (position < start))
     return -1;
 
-  if (segment->rate > 0.0) {
+  if (G_LIKELY (segment->rate > 0.0)) {
     /* outside of the segment boundary stop */
     if (G_UNLIKELY (stop != -1 && position > stop))
       return -1;
@@ -683,7 +683,7 @@ gst_segment_to_running_time (GstSegment * segment, GstFormat format,
 
   /* scale based on the rate, avoid division by and conversion to 
    * float when not needed */
-  if (segment->abs_rate != 1.0)
+  if (G_UNLIKELY (segment->abs_rate != 1.0))
     result /= segment->abs_rate;
 
   /* correct for accumulated segments */
@@ -761,3 +761,73 @@ gst_segment_clip (GstSegment * segment, GstFormat format, gint64 start,
 
   return TRUE;
 }
+
+/**
+ * gst_segment_to_position:
+ * @segment: a #GstSegment structure.
+ * @format: the format of the segment.
+ * @running_time: the running_time in the segment
+ *
+ * Convert @running_time into a position in the segment so that
+ * gst_segment_to_running_time() with that position returns @running_time.
+ *
+ * Returns: the position in the segment for @running_time.
+ *
+ * Since: 0.10.24
+ */
+gint64
+gst_segment_to_position (GstSegment * segment, GstFormat format,
+    gint64 running_time)
+{
+  gint64 result;
+  gint64 start, stop, accum;
+
+  g_return_val_if_fail (segment != NULL, -1);
+
+  if (G_UNLIKELY (running_time == -1))
+    return -1;
+
+  if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED))
+    segment->format = format;
+
+  /* if we have the position for the same format as the segment, we can compare
+   * the start and stop values, otherwise we assume 0 and -1 */
+  if (G_LIKELY (segment->format == format)) {
+    start = segment->start;
+    stop = segment->stop;
+    accum = segment->accum;
+  } else {
+    start = 0;
+    stop = -1;
+    accum = 0;
+  }
+
+  /* this running_time was for a previous segment */
+  if (running_time < accum)
+    return -1;
+
+  /* start by subtracting the accumulated time */
+  result = running_time - accum;
+
+  /* move into the segment at the right rate */
+  if (G_UNLIKELY (segment->abs_rate != 1.0))
+    result *= segment->abs_rate;
+
+  if (G_LIKELY (segment->rate > 0.0)) {
+    /* bring to corrected position in segment */
+    result += start;
+
+    /* outside of the segment boundary stop */
+    if (G_UNLIKELY (stop != -1 && result > stop))
+      return -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;
+  }
+  return result;
+}
index 18c728b..6f66c06 100644 (file)
@@ -96,6 +96,7 @@ void         gst_segment_set_newsegment_full (GstSegment *segment, gboolean upda
 
 gint64       gst_segment_to_stream_time      (GstSegment *segment, GstFormat format, gint64 position);
 gint64       gst_segment_to_running_time     (GstSegment *segment, GstFormat format, gint64 position);
+gint64       gst_segment_to_position         (GstSegment *segment, GstFormat format, gint64 running_time);
 
 gboolean     gst_segment_clip                (GstSegment *segment, GstFormat format, gint64 start,
                                               gint64 stop, gint64 *clip_start, gint64 *clip_stop);
index eba1271..8e489d4 100644 (file)
@@ -1341,17 +1341,25 @@ GST_START_TEST (segment_newsegment_runningtime)
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 0);
   fail_unless (result == 0);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 0);
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 100);
   fail_unless (result == 100);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 100);
 
   /* at edge is exactly the segment duration */
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 200);
   fail_unless (result == 200);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 200);
 
   /* outside of the segment */
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 300);
   fail_unless (result == -1);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, 300);
+  fail_unless (result == -1);
 
   /***********************************************************
    * time shifted by 500, check if accumulation worked.
@@ -1371,13 +1379,19 @@ GST_START_TEST (segment_newsegment_runningtime)
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 0);
   fail_unless (result == 200);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 0);
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 100);
   fail_unless (result == 250);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 100);
 
   /* outside of the segment */
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 500);
   fail_unless (result == -1);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, 310);
+  fail_unless (result == -1);
 
   /********************************************
    * time offset by 500
@@ -1397,19 +1411,29 @@ GST_START_TEST (segment_newsegment_runningtime)
   /* before segment is invalid */
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 400);
   fail_unless (result == -1);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, 200);
+  fail_unless (result == -1);
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 500);
   fail_unless (result == 300);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 500);
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 600);
   fail_unless (result == 400);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 600);
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 700);
   fail_unless (result == 500);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 700);
 
   /* outside of the segment */
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 800);
   fail_unless (result == -1);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, 600);
+  fail_unless (result == -1);
 
   /**********************************************************
    * time offset by 500, shifted by 200
@@ -1429,19 +1453,29 @@ GST_START_TEST (segment_newsegment_runningtime)
   /* before segment is invalid */
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 400);
   fail_unless (result == -1);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, 400);
+  fail_unless (result == -1);
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 500);
   fail_unless (result == 700);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 500);
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 600);
   fail_unless (result == 600);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 600);
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 700);
   fail_unless (result == 500);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 700);
 
   /* outside of the segment */
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 800);
   fail_unless (result == -1);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, 800);
+  fail_unless (result == -1);
 
   /**********************************************************
    * time offset by 500, shifted by 200
@@ -1461,20 +1495,30 @@ GST_START_TEST (segment_newsegment_runningtime)
   /* before segment is invalid */
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 400);
   fail_unless (result == -1);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, 600);
+  fail_unless (result == -1);
 
   /* total scaled segment time is 100, accum is 700, so we get 800 */
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 500);
   fail_unless (result == 800);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 500);
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 600);
   fail_unless (result == 750);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 600);
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 700);
   fail_unless (result == 700);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 700);
 
   /* outside of the segment */
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 800);
   fail_unless (result == -1);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, 900);
+  fail_unless (result == -1);
 
   /* see if negative rate closed segment correctly */
   gst_segment_set_newsegment_full (&segment, FALSE, -2.0, -1.0,
@@ -1482,6 +1526,8 @@ GST_START_TEST (segment_newsegment_runningtime)
 
   /* previous segment lasted 100, and was at 700 so we should get 800 */
   fail_unless (segment.accum == 800);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, 800);
+  fail_unless (result == 700);
 }
 
 GST_END_TEST;
@@ -1517,9 +1563,13 @@ GST_START_TEST (segment_newsegment_accum)
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 200);
   fail_unless (result == 0);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 200);
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 150);
   fail_unless (result == 50);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 150);
 
   /* update segment, this accumulates 50 from the previous segment. */
   gst_segment_set_newsegment_full (&segment, TRUE, -2.0, 1.0,
@@ -1538,10 +1588,14 @@ GST_START_TEST (segment_newsegment_accum)
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 150);
   fail_unless (result == 50);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 150);
 
   /* 50 accumulated + 50 / 2 */
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 100);
   fail_unless (result == 75);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 100);
 
   /* update segment, this does not accumulate anything. */
   gst_segment_set_newsegment_full (&segment, TRUE, 1.0, 1.0,
@@ -1560,9 +1614,13 @@ GST_START_TEST (segment_newsegment_accum)
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 100);
   fail_unless (result == 50);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 100);
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 150);
   fail_unless (result == 100);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 150);
 }
 
 GST_END_TEST;
@@ -1595,12 +1653,18 @@ GST_START_TEST (segment_newsegment_accum2)
   /* invalid time gives invalid result */
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, -1);
   fail_unless (result == -1);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == -1);
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 200);
   fail_unless (result == 0);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 200);
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 150);
   fail_unless (result == 50);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 150);
 
   /* close segment, this accumulates nothing. */
   gst_segment_set_newsegment_full (&segment, TRUE, -1.0, 1.0,
@@ -1638,9 +1702,13 @@ GST_START_TEST (segment_newsegment_accum2)
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 150);
   fail_unless (result == 50);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 150);
 
   result = gst_segment_to_running_time (&segment, GST_FORMAT_TIME, 200);
   fail_unless (result == 100);
+  result = gst_segment_to_position (&segment, GST_FORMAT_TIME, result);
+  fail_unless (result == 200);
 }
 
 GST_END_TEST;
index f7cc829..55a41e2 100644 (file)
@@ -836,6 +836,7 @@ EXPORTS
        gst_segment_set_newsegment
        gst_segment_set_newsegment_full
        gst_segment_set_seek
+       gst_segment_to_position
        gst_segment_to_running_time
        gst_segment_to_stream_time
        gst_segtrap_is_enabled