summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWim Taymans <wtaymans@redhat.com>2015-03-18 11:31:51 +0100
committerWim Taymans <wtaymans@redhat.com>2015-03-18 11:35:42 +0100
commit8c8b3818e44198d2369fbbbf103bc889083ba87b (patch)
tree40a3b1b6bb947707f35c5be31854d12c55c88db4
parent6e67ad7675c3bd00dae00c5aa20647f7e241802a (diff)
segment: add helper to get negative running-time
Add a helper method to get a running-time with a little more features such as detecting if the value was before or after the segment and negative running-time. API: gst_segment_to_running_time_full() Fixes https://bugzilla.gnome.org/show_bug.cgi?id=740575
-rw-r--r--gst/gstsegment.c171
-rw-r--r--gst/gstsegment.h24
-rw-r--r--tests/check/gst/gstsegment.c42
-rw-r--r--win32/common/libgstreamer.def2
4 files changed, 191 insertions, 48 deletions
diff --git a/gst/gstsegment.c b/gst/gstsegment.c
index 2f1b037ad..e132c65bf 100644
--- a/gst/gstsegment.c
+++ b/gst/gstsegment.c
@@ -453,93 +453,168 @@ gst_segment_to_stream_time (const GstSegment * segment, GstFormat format,
}
/**
- * gst_segment_to_running_time:
+ * gst_segment_to_running_time_full:
* @segment: a #GstSegment structure.
* @format: the format of the segment.
* @position: the position in the segment
+ * @running_time: result running-time
*
* Translate @position to the total running time using the currently configured
- * segment. Position is a value between @segment start and stop time.
+ * segment. Position is a value between @segment start and stop time. Compared to
+ * gst_segment_to_running_time() this function can return negative running-time
+ * and specify if the position was before or after the segment incase it is outside
+ * of the segment.
*
- * This function is typically used by elements that need to synchronize to the
- * global clock in a pipeline. The running time is a constantly increasing value
- * starting from 0. When gst_segment_init() is called, this value will reset to
- * 0.
+ * This function is typically used by elements that need to synchronize buffers
+ * against the clock or eachother.
*
- * This function returns -1 if the position is outside of @segment start and stop.
+ * When #GST_SEGMENT_RESULT_OK is returned, @position is between start and stop of
+ * @segment and thus resulted in a positive running-time returned in @running_time.
*
- * Returns: the position as the total running time or -1 when an invalid position
- * was given.
+ * When @position is outside of the segment start and stop values,
+ * #GST_SEGMENT_RESULT_BEFORE or #GST_SEGMENT_RESULT_AFTER is returned depending
+ * if @position is respectively before or after the segment.
+ *
+ * When this function returns #GST_SEGMENT_RESULT_NEGATIVE, the returned
+ * @running_time should be negated to get the real negative running time.
+ *
+ * Returns: a #GstSegmentResult
+ *
+ * Since: 1.6
*/
-guint64
-gst_segment_to_running_time (const GstSegment * segment, GstFormat format,
- guint64 position)
+GstSegmentResult
+gst_segment_to_running_time_full (const GstSegment * segment, GstFormat format,
+ guint64 position, guint64 * running_time)
{
+ GstSegmentResult res;
guint64 result;
- guint64 start, stop;
+ guint64 start, stop, offset;
gdouble abs_rate;
if (G_UNLIKELY (position == -1)) {
GST_DEBUG ("invalid position (-1)");
- return -1;
+ res = GST_SEGMENT_RESULT_INVALID;
+ goto done;
}
- g_return_val_if_fail (segment != NULL, -1);
- g_return_val_if_fail (segment->format == format, -1);
+ g_return_val_if_fail (segment != NULL, GST_SEGMENT_RESULT_INVALID);
+ g_return_val_if_fail (segment->format == format, GST_SEGMENT_RESULT_INVALID);
start = segment->start;
-
- if (segment->rate > 0.0)
- start += segment->offset;
-
/* before the segment boundary */
if (G_UNLIKELY (position < start)) {
GST_DEBUG ("position(%" G_GUINT64_FORMAT ") < start(%" G_GUINT64_FORMAT
")", position, start);
- return -1;
+ if (G_LIKELY (segment->rate > 0.0))
+ res = GST_SEGMENT_RESULT_BEFORE;
+ else
+ res = GST_SEGMENT_RESULT_AFTER;
+ goto done;
}
stop = segment->stop;
+ /* after the segment boundary */
+ if (G_UNLIKELY (stop != -1 && position > stop)) {
+ GST_DEBUG ("position(%" G_GUINT64_FORMAT ") > stop(%" G_GUINT64_FORMAT
+ ")", position, stop);
+ if (G_LIKELY (segment->rate > 0.0))
+ res = GST_SEGMENT_RESULT_AFTER;
+ else
+ res = GST_SEGMENT_RESULT_BEFORE;
+ goto done;
+ }
+
+ offset = segment->offset;
if (G_LIKELY (segment->rate > 0.0)) {
- /* after of the segment boundary */
- if (G_UNLIKELY (stop != -1 && position > stop)) {
- GST_DEBUG ("position(%" G_GUINT64_FORMAT ") > stop(%" G_GUINT64_FORMAT
- ")", position, stop);
- return -1;
+ /* bring to uncorrected position in segment */
+ if (position < start + offset) {
+ /* negative value */
+ result = (start + offset) - position;
+ res = GST_SEGMENT_RESULT_NEGATIVE;
+ } else {
+ result = position - (start + offset);
+ res = GST_SEGMENT_RESULT_OK;
}
+ } else {
+ /* cannot continue if no stop position set or invalid offset */
+ g_return_val_if_fail (stop != -1, GST_SEGMENT_RESULT_INVALID);
+ g_return_val_if_fail (stop >= segment->offset, GST_SEGMENT_RESULT_INVALID);
/* bring to uncorrected position in segment */
- result = position - start;
- } else {
- /* cannot continue if no stop position set or outside of
- * the segment. */
- if (G_UNLIKELY (stop == -1)) {
- GST_DEBUG ("invalid stop (-1)");
- return -1;
+ if (position > stop - offset) {
+ /* negative value */
+ result = position - (stop - offset);
+ res = GST_SEGMENT_RESULT_NEGATIVE;
+ } else {
+ result = (stop - offset) - position;
+ res = GST_SEGMENT_RESULT_OK;
}
+ }
- stop -= segment->offset;
- if (G_UNLIKELY (position > stop)) {
- GST_DEBUG ("position(%" G_GUINT64_FORMAT ") > stop(%" G_GUINT64_FORMAT
- ")", position, stop);
- return -1;
+ if (running_time) {
+ /* scale based on the rate, avoid division by and conversion to
+ * float when not needed */
+ abs_rate = ABS (segment->rate);
+ if (G_UNLIKELY (abs_rate != 1.0))
+ result /= abs_rate;
+
+ /* correct for base of the segment */
+ if (res == GST_SEGMENT_RESULT_OK)
+ /* positive, add base */
+ *running_time = result + segment->base;
+ else if (segment->base >= result) {
+ /* negative and base is bigger, subtract from base and we have a
+ * positive value again */
+ *running_time = segment->base - result;
+ res = GST_SEGMENT_RESULT_OK;
+ } else {
+ /* negative and base is smaller, subtract base and remainder is
+ * negative */
+ *running_time = result - segment->base;
}
+ }
+ return res;
- /* bring to uncorrected position in segment */
- result = stop - position;
+done:
+ {
+ if (running_time)
+ *running_time = -1;
+ return res;
}
+}
- /* scale based on the rate, avoid division by and conversion to
- * float when not needed */
- abs_rate = ABS (segment->rate);
- if (G_UNLIKELY (abs_rate != 1.0))
- result /= abs_rate;
+/**
+ * gst_segment_to_running_time:
+ * @segment: a #GstSegment structure.
+ * @format: the format of the segment.
+ * @position: the position in the segment
+ *
+ * Translate @position to the total running time using the currently configured
+ * segment. Position is a value between @segment start and stop time.
+ *
+ * This function is typically used by elements that need to synchronize to the
+ * global clock in a pipeline. The running time is a constantly increasing value
+ * starting from 0. When gst_segment_init() is called, this value will reset to
+ * 0.
+ *
+ * This function returns -1 if the position is outside of @segment start and stop.
+ *
+ * Returns: the position as the total running time or -1 when an invalid position
+ * was given.
+ */
+guint64
+gst_segment_to_running_time (const GstSegment * segment, GstFormat format,
+ guint64 position)
+{
+ guint64 result;
+ GstSegmentResult res;
- /* correct for base of the segment */
- result += segment->base;
+ res = gst_segment_to_running_time_full (segment, format, position, &result);
+ if (res == GST_SEGMENT_RESULT_OK)
+ return result;
- return result;
+ return -1;
}
/**
diff --git a/gst/gstsegment.h b/gst/gstsegment.h
index 4787e49fc..29212b9f0 100644
--- a/gst/gstsegment.h
+++ b/gst/gstsegment.h
@@ -169,6 +169,27 @@ typedef enum { /*< flags >*/
} GstSegmentFlags;
/**
+ * GstSegmentResult:
+ * @GST_SEGMENT_RESULT_INVALID: input value is invalid and no output value can
+ * be calculated.
+ * @GST_SEGMENT_RESULT_OK: value is within the segment and positive.
+ * @GST_SEGMENT_RESULT_NEGATIVE: value is within the segment but negative.
+ * @GST_SEGMENT_RESULT_BEFORE: value is outside before the segment.
+ * @GST_SEGMENT_RESULT_AFTER: value is outside after the segment.
+ *
+ * Possible return values from gst_segment_to_running_time_full().
+ *
+ * Since: 1.6
+ */
+typedef enum {
+ GST_SEGMENT_RESULT_INVALID = 0,
+ GST_SEGMENT_RESULT_OK = 1,
+ GST_SEGMENT_RESULT_NEGATIVE = -1,
+ GST_SEGMENT_RESULT_BEFORE = -2,
+ GST_SEGMENT_RESULT_AFTER = -3
+} GstSegmentResult;
+
+/**
* GstSegment:
* @flags: flags for this segment
* @rate: the rate of the segment
@@ -217,6 +238,9 @@ void gst_segment_init (GstSegment *segment, GstFormat for
guint64 gst_segment_to_stream_time (const GstSegment *segment, GstFormat format, guint64 position);
guint64 gst_segment_to_running_time (const GstSegment *segment, GstFormat format, guint64 position);
+GstSegmentResult
+ gst_segment_to_running_time_full (const GstSegment *segment, GstFormat format, guint64 position,
+ guint64 * running_time);
guint64 gst_segment_to_position (const GstSegment *segment, GstFormat format, guint64 running_time);
gboolean gst_segment_set_running_time (GstSegment *segment, GstFormat format, guint64 running_time);
diff --git a/tests/check/gst/gstsegment.c b/tests/check/gst/gstsegment.c
index 3e5f16b8f..8f642d572 100644
--- a/tests/check/gst/gstsegment.c
+++ b/tests/check/gst/gstsegment.c
@@ -30,6 +30,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);
+ GST_DEBUG ("position %" G_GUINT64_FORMAT ", st %" G_GUINT64_FORMAT ", rt %"
+ G_GUINT64_FORMAT, position, stream_time, running_time);
fail_unless_equals_int64 (st, stream_time);
fail_unless_equals_int64 (rt, running_time);
@@ -744,6 +746,45 @@ GST_START_TEST (segment_offset)
GST_END_TEST;
+GST_START_TEST (segment_full)
+{
+ GstSegment segment;
+ guint64 rt;
+
+ gst_segment_init (&segment, GST_FORMAT_TIME);
+
+ segment.start = 50;
+ segment.position = 150;
+ segment.stop = 200;
+ segment.time = 0;
+
+ check_times (&segment, 100, 50, 50);
+ check_times (&segment, 220, -1, -1);
+
+ fail_unless (gst_segment_to_running_time_full (&segment, GST_FORMAT_TIME,
+ 50, &rt) == GST_SEGMENT_RESULT_OK);
+ fail_unless (rt == 0);
+ fail_unless (gst_segment_to_running_time_full (&segment, GST_FORMAT_TIME,
+ 200, &rt) == GST_SEGMENT_RESULT_OK);
+ fail_unless (rt == 150);
+ fail_unless (gst_segment_to_running_time_full (&segment, GST_FORMAT_TIME,
+ 40, &rt) == GST_SEGMENT_RESULT_BEFORE);
+ fail_unless (gst_segment_to_running_time_full (&segment, GST_FORMAT_TIME,
+ 49, &rt) == GST_SEGMENT_RESULT_BEFORE);
+ fail_unless (gst_segment_to_running_time_full (&segment, GST_FORMAT_TIME,
+ 201, &rt) == GST_SEGMENT_RESULT_AFTER);
+
+ fail_unless (gst_segment_offset_running_time (&segment, GST_FORMAT_TIME,
+ -50) == TRUE);
+ fail_unless (segment.offset == 50);
+
+ fail_unless (gst_segment_to_running_time_full (&segment, GST_FORMAT_TIME,
+ 50, &rt) == GST_SEGMENT_RESULT_NEGATIVE);
+ GST_DEBUG ("%" G_GUINT64_FORMAT, rt);
+ fail_unless (rt == 50);
+}
+
+GST_END_TEST;
static Suite *
gst_segment_suite (void)
@@ -761,6 +802,7 @@ gst_segment_suite (void)
tcase_add_test (tc_chain, segment_copy);
tcase_add_test (tc_chain, segment_seek_noupdate);
tcase_add_test (tc_chain, segment_offset);
+ tcase_add_test (tc_chain, segment_full);
return s;
}
diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def
index 22acb9db2..e21f49800 100644
--- a/win32/common/libgstreamer.def
+++ b/win32/common/libgstreamer.def
@@ -1124,9 +1124,11 @@ EXPORTS
gst_segment_init
gst_segment_new
gst_segment_offset_running_time
+ gst_segment_result_get_type
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_segtrap_is_enabled
gst_segtrap_set_enabled