diff --git a/docs/design/part-synchronisation.txt b/docs/design/part-synchronisation.txt index 3c0dcd1405..cac9f07376 100644 --- a/docs/design/part-synchronisation.txt +++ b/docs/design/part-synchronisation.txt @@ -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. diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index 5f5e5777f5..512d579a93 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -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 diff --git a/gst/gstsegment.c b/gst/gstsegment.c index 2307ded1f2..b7c31f282c 100644 --- a/gst/gstsegment.c +++ b/gst/gstsegment.c @@ -374,6 +374,114 @@ gst_segment_do_seek (GstSegment * segment, gdouble rate, return TRUE; } +/** + * 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. @@ -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; + } + + if (gst_segment_to_stream_time_full (segment, format, position, &result) == 1) + return result; + + 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; - - /* before the segment boundary */ - if (G_UNLIKELY (position < start)) - return -1; - 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)) + res = + gst_segment_position_from_stream_time_full (segment, format, stream_time, + &position); + + /* 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; - - /* time must be known */ - if (G_UNLIKELY (time == -1)) - 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; } - return position; + /* 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; + } + + 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 position; + gint res; + + g_return_val_if_fail (segment != NULL, -1); + g_return_val_if_fail (segment->format == format, -1); + + res = + gst_segment_position_from_running_time_full (segment, format, + running_time, &position); + + 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; + } + + 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)) - return -1; + if (G_UNLIKELY (running_time == -1)) { + *position = -1; + return 0; + } - g_return_val_if_fail (segment != NULL, -1); - g_return_val_if_fail (segment->format == format, FALSE); + g_return_val_if_fail (segment != NULL, 0); + g_return_val_if_fail (segment->format == format, 0); base = segment->base; - /* this running_time was for a previous segment */ - if (running_time < base) - return -1; - - /* start by subtracting the base time */ - result = running_time - 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; } /** diff --git a/gst/gstsegment.h b/gst/gstsegment.h index 6c4634a440..5487123401 100644 --- a/gst/gstsegment.h +++ b/gst/gstsegment.h @@ -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); diff --git a/tests/check/gst/gstsegment.c b/tests/check/gst/gstsegment.c index 78e0688b57..f3433e8083 100644 --- a/tests/check/gst/gstsegment.c +++ b/tests/check/gst/gstsegment.c @@ -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; } diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index f21679b41c..10dad7ae30 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -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