From 8c8b3818e44198d2369fbbbf103bc889083ba87b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 18 Mar 2015 11:31:51 +0100 Subject: [PATCH] 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 --- gst/gstsegment.c | 171 ++++++++++++++++++++++++++++++------------ gst/gstsegment.h | 24 ++++++ tests/check/gst/gstsegment.c | 42 +++++++++++ win32/common/libgstreamer.def | 2 + 4 files changed, 191 insertions(+), 48 deletions(-) diff --git a/gst/gstsegment.c b/gst/gstsegment.c index 2f1b037..e132c65 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 4787e49..29212b9 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 3e5f16b..8f642d5 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 22acb9d..e21f498 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 -- 2.7.4