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
This commit is contained in:
Vivia Nikolaidou 2015-10-19 16:50:51 +03:00 committed by Sebastian Dröge
parent fb39b3853f
commit 5cccf9846f
2 changed files with 95 additions and 11 deletions

View file

@ -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;

View file

@ -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;
}