From 5cccf9846f02150f445253119634a08aad9ffda5 Mon Sep 17 00:00:00 2001 From: Vivia Nikolaidou Date: Mon, 19 Oct 2015 16:50:51 +0300 Subject: [PATCH] segment: Correct stream_time calc for negative applied rate Updated gst_segment_position_from_stream_time and gst_segment_to_stream_time to reflect correct calculations for the case when the applied rate is negative. Pasting from design docs: =============================== 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 For negative rates, B.timestamp will go backwards from S.stop to S.start, making the stream time go backwards. =============================== Therefore, the calculation for applied_rate < 0 should be: stream_time = (S.stop - B.timestamp) * ABS (S.applied_rate) + S.time and the reverse: B.timestamp = S.stop - (stream_time - S.time) / ABS (S.applied_rate) https://bugzilla.gnome.org/show_bug.cgi?id=756810 --- gst/gstsegment.c | 24 ++++++----- tests/check/gst/gstsegment.c | 82 ++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 11 deletions(-) diff --git a/gst/gstsegment.c b/gst/gstsegment.c index 62fb61958a..2594d53383 100644 --- a/gst/gstsegment.c +++ b/gst/gstsegment.c @@ -426,27 +426,29 @@ gst_segment_to_stream_time (const GstSegment * segment, GstFormat format, if (G_UNLIKELY (time == -1)) return -1; - /* bring to uncorrected position in segment */ - stream_time = position - start; - abs_applied_rate = ABS (segment->applied_rate); - /* correct for applied rate if needed */ - if (G_UNLIKELY (abs_applied_rate != 1.0)) - stream_time *= abs_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; + /* 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; } 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_LIKELY (time > stream_time)) - stream_time = time - stream_time; - else - stream_time = 0; + if (G_UNLIKELY (position > stop)) + return -1; + stream_time = stop - position; + if (G_UNLIKELY (abs_applied_rate != 1.0)) + stream_time *= abs_applied_rate; + stream_time += time; } return stream_time; diff --git a/tests/check/gst/gstsegment.c b/tests/check/gst/gstsegment.c index 867891590a..f0efd9fdac 100644 --- a/tests/check/gst/gstsegment.c +++ b/tests/check/gst/gstsegment.c @@ -792,6 +792,86 @@ GST_START_TEST (segment_full) GST_END_TEST; +GST_START_TEST (segment_negative_rate) +{ + GstSegment segment; + + gst_segment_init (&segment, GST_FORMAT_TIME); + + segment.start = 50; + segment.position = 150; + segment.stop = 200; + segment.time = 0; + segment.applied_rate = -1; + segment.rate = -1; + + /* somewhere in the middle */ + check_times (&segment, 100, 100, 100); + /* after stop */ + check_times (&segment, 220, -1, -1); + /* before start */ + check_times (&segment, 10, -1, -1); + /* at segment start */ + check_times (&segment, 50, 150, 150); + /* another place in the middle */ + check_times (&segment, 150, 50, 50); + /* at segment stop */ + check_times (&segment, 200, 0, 0); + + segment.time = 100; + segment.base = 100; + /* somewhere in the middle */ + check_times (&segment, 100, 200, 200); + /* at segment start */ + check_times (&segment, 50, 250, 250); + /* another place in the middle */ + check_times (&segment, 150, 150, 150); + /* at segment stop */ + check_times (&segment, 200, 100, 100); +} + +GST_END_TEST; + +GST_START_TEST (segment_negative_applied_rate) +{ + GstSegment segment; + + gst_segment_init (&segment, GST_FORMAT_TIME); + + segment.start = 50; + segment.position = 150; + segment.stop = 200; + segment.time = 0; + segment.applied_rate = -1; + segment.rate = 1; + + /* somewhere in the middle */ + check_times (&segment, 100, 100, 50); + /* after stop */ + check_times (&segment, 220, -1, -1); + /* before start */ + check_times (&segment, 10, -1, -1); + /* at segment start */ + check_times (&segment, 50, 150, 0); + /* another place in the middle */ + check_times (&segment, 150, 50, 100); + /* at segment stop */ + check_times (&segment, 200, 0, 150); + + segment.time = 100; + segment.base = 100; + /* somewhere in the middle */ + check_times (&segment, 100, 200, 150); + /* at segment start */ + check_times (&segment, 50, 250, 100); + /* another place in the middle */ + check_times (&segment, 150, 150, 200); + /* at segment stop */ + check_times (&segment, 200, 100, 250); +} + +GST_END_TEST; + static Suite * gst_segment_suite (void) { @@ -809,6 +889,8 @@ gst_segment_suite (void) tcase_add_test (tc_chain, segment_seek_noupdate); tcase_add_test (tc_chain, segment_offset); tcase_add_test (tc_chain, segment_full); + tcase_add_test (tc_chain, segment_negative_rate); + tcase_add_test (tc_chain, segment_negative_applied_rate); return s; }