docs/design/part-synchronisation.txt: Small updates.

Original commit message from CVS:
* docs/design/part-synchronisation.txt:
Small updates.
* gst/gstsegment.c: (gst_segment_set_seek),
(gst_segment_set_newsegment_full), (gst_segment_to_stream_time),
(gst_segment_to_running_time):
The seek format can be different from the segment format when the start
and stop values are not to be updated, when we only do a rate change for
example.
* tests/check/gst/gstsegment.c: (GST_START_TEST),
(gst_segment_suite):
Add a testcase for the rate-only seeks, checking that the format is
correctly ignored when start and stop are not updated.
This commit is contained in:
Wim Taymans 2007-12-19 12:48:18 +00:00
parent 3c718ae9f4
commit a332964e6c
5 changed files with 184 additions and 21 deletions

View file

@ -1,3 +1,20 @@
2007-12-19 Wim Taymans <wim.taymans@collabora.co.uk>
* docs/design/part-synchronisation.txt:
Small updates.
* gst/gstsegment.c: (gst_segment_set_seek),
(gst_segment_set_newsegment_full), (gst_segment_to_stream_time),
(gst_segment_to_running_time):
The seek format can be different from the segment format when the start
and stop values are not to be updated, when we only do a rate change for
example.
* tests/check/gst/gstsegment.c: (GST_START_TEST),
(gst_segment_suite):
Add a testcase for the rate-only seeks, checking that the format is
correctly ignored when start and stop are not updated.
2007-12-18 Sebastian Dröge <slomo@circular-chaos.org>
Patch by: Matthias Bolte <photon at mail dot upb dot de>

2
common

@ -1 +1 @@
Subproject commit 67b8f4e3c576945f4d778c9040876af3a5a0756e
Subproject commit 970759077c95ee4e85650db023ac6f974e2aa5e1

View file

@ -59,15 +59,18 @@ The clock and pipeline now provides a running_time to all elements that want to
perform synchronisation. Indeed, the running time can be observed in each
element (during the PLAYING state) as:
running_time = absolute_time - base_time
C.running_time = absolute_time - base_time
We note C.running_time as the running_time obtained by looking at the clock.
This value is monotonically increasing at the rate of the clock.
Timestamps
----------
The GstBuffer timestamps and the preceeding NEW_SEGMENT event (See
part-streams.txt) define a transformation of the buffers to running_time as
follows:
part-streams.txt) define a transformation of the buffer timestamps to
running_time as follows:
The following notation is used:
@ -76,6 +79,7 @@ The following notation is used:
NS: NEWSEGMENT event preceeding the buffers.
- NS.start: start field in the NEWSEGMENT event
- NS.stop: stop field in the NEWSEGMENT event
- NS.rate: rate field of NEWSEGMENT event
- NS.abs_rate: absolute value of rate field of NEWSEGMENT event
- NS.time: time field in the NEWSEGMENT event
@ -89,9 +93,12 @@ to these boundaries (see also part-segments.txt).
The following transformation to running_time exist:
if (NS.rate > 0.0)
running_time = (B.timestamp - NS.start) / NS.abs_rate + NS.accum
B.running_time = (B.timestamp - NS.start) / NS.abs_rate + NS.accum
else
running_time = (NS.stop - B.timestamp) / NS.abs_rate + NS.accum
B.running_time = (NS.stop - B.timestamp) / NS.abs_rate + NS.accum
We write B.running_time as the running_time obtained from the NEWSEGMENT event
and the buffers of that segment.
The first displayable buffer will yield a value of 0 (since B.timestamp ==
NS.start and NS.accum == 0).
@ -100,7 +107,7 @@ For NS.rate > 1.0, the timestamps will be scaled down to increase the playback
rate. Likewise, a rate between 0.0 and 1.0 will slow down playback.
For negative rates, timestamps are received stop NS.stop to NS.start so that the
first buffer received will be transformed into running_time of 0 (B.timestamp ==
first buffer received will be transformed into B.running_time of 0 (B.timestamp ==
NS.stop and NS.accum == 0).
@ -121,7 +128,7 @@ As we have seen, we can get a running_time:
We prefix C. and B. before the two running times to note how they were
calculated.
The task of synchronized playback is to make sure that we play be buffer with
The task of synchronized playback is to make sure that we play a buffer with
B.running_time at the moment when the clock reaches the same C.running_time.
Thus the following must hold:
@ -162,7 +169,7 @@ between 0 and the total duration of the media file.
It is the stream time that is used for:
- report the POSITION query in the pipeline
- the position used in seek queries
- the position used in seek events/queries
- the position used to synchronize controller values
Stream time is calculated using the buffer times and the preceeding NEWSEGMENT

View file

@ -274,15 +274,13 @@ gst_segment_set_seek (GstSegment * segment, gdouble rate,
if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED))
segment->format = format;
else
g_return_if_fail (segment->format == format);
update_start = update_stop = TRUE;
/* start is never invalid */
/* segment->start is never invalid */
switch (start_type) {
case GST_SEEK_TYPE_NONE:
/* no update to segment */
/* no update to segment, take previous start */
start = segment->start;
update_start = FALSE;
break;
@ -290,13 +288,17 @@ gst_segment_set_seek (GstSegment * segment, gdouble rate,
/* start holds desired position, map -1 to the start */
if (start == -1)
start = 0;
/* start must be 0 or the formats must match */
g_return_if_fail (start == 0 || segment->format == format);
break;
case GST_SEEK_TYPE_CUR:
/* add start to currently configure segment */
g_return_if_fail (start == 0 || segment->format == format);
/* add start to currently configured segment */
start = segment->start + start;
break;
case GST_SEEK_TYPE_END:
if (segment->duration != -1) {
g_return_if_fail (start == 0 || segment->format == format);
/* add start to total length */
start = segment->duration + start;
} else {
@ -319,18 +321,24 @@ gst_segment_set_seek (GstSegment * segment, gdouble rate,
update_stop = FALSE;
break;
case GST_SEEK_TYPE_SET:
/* stop holds required value */
/* stop holds required value, if it's not -1, it must be of the same
* format as the segment. */
g_return_if_fail (stop == -1 || segment->format == format);
break;
case GST_SEEK_TYPE_CUR:
if (segment->stop != -1)
if (segment->stop != -1) {
/* only add compatible formats or 0 */
g_return_if_fail (stop == 0 || segment->format == format);
stop = segment->stop + stop;
else
} else
stop = -1;
break;
case GST_SEEK_TYPE_END:
if (segment->duration != -1)
if (segment->duration != -1) {
/* only add compatible formats or 0 */
g_return_if_fail (stop == 0 || segment->format == format);
stop = segment->duration + stop;
else {
} else {
stop = segment->stop;
update_stop = FALSE;
}
@ -373,8 +381,7 @@ gst_segment_set_seek (GstSegment * segment, gdouble rate,
*update = last_stop != segment->last_stop;
/* update new position */
if (last_stop != segment->last_stop)
segment->last_stop = last_stop;
segment->last_stop = last_stop;
segment->time = start;
segment->stop = stop;

View file

@ -435,6 +435,137 @@ GST_START_TEST (segment_seek_reverse)
GST_END_TEST;
/* mess with the segment structure in the bytes format */
GST_START_TEST (segment_seek_rate)
{
GstSegment segment;
gboolean update;
gst_segment_init (&segment, GST_FORMAT_BYTES);
/* configure segment to rate 2.0, format does not matter when we don't specify
* a start or stop position. */
gst_segment_set_seek (&segment, 2.0,
GST_FORMAT_UNDEFINED,
GST_SEEK_FLAG_NONE,
GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_NONE, -1, &update);
fail_unless (segment.format == GST_FORMAT_BYTES);
fail_unless (segment.start == 0);
fail_unless (segment.stop == -1);
fail_unless (segment.rate == 2.0);
fail_unless (update == FALSE);
/* 0 is the same in all formats and should not fail */
gst_segment_set_seek (&segment, 2.0,
GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1, &update);
fail_unless (segment.format == GST_FORMAT_BYTES);
/* set to -1 means start from 0 */
gst_segment_set_seek (&segment, 2.0,
GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
GST_SEEK_TYPE_SET, -1, GST_SEEK_TYPE_NONE, -1, &update);
fail_unless (segment.format == GST_FORMAT_BYTES);
fail_unless (segment.start == 0);
gst_segment_set_seek (&segment, 2.0,
GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
GST_SEEK_TYPE_CUR, 0, GST_SEEK_TYPE_NONE, -1, &update);
gst_segment_set_seek (&segment, 2.0,
GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
GST_SEEK_TYPE_END, 0, GST_SEEK_TYPE_NONE, -1, &update);
/* -1 for end is fine too in all formats */
gst_segment_set_seek (&segment, 2.0,
GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_SET, -1, &update);
/* 0 as relative end is fine too */
gst_segment_set_seek (&segment, 2.0,
GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_CUR, 0, &update);
gst_segment_set_seek (&segment, 2.0,
GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_END, 0, &update);
/* set a real stop position, this must happen in bytes */
gst_segment_set_seek (&segment, 3.0,
GST_FORMAT_BYTES,
GST_SEEK_FLAG_NONE,
GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_SET, 100, &update);
fail_unless (segment.format == GST_FORMAT_BYTES);
fail_unless (segment.start == 0);
fail_unless (segment.stop == 100);
fail_unless (segment.rate == 3.0);
/* no seek should happen, we just updated the stop position in forward
* playback mode.*/
fail_unless (update == FALSE);
/* 0 as relative end is fine too */
gst_segment_set_seek (&segment, 2.0,
GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_CUR, 0, &update);
fail_unless (segment.stop == 100);
gst_segment_set_seek (&segment, 2.0,
GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_END, 0, &update);
fail_unless (segment.stop == 100);
/* -1 for end is fine too in all formats */
gst_segment_set_seek (&segment, 2.0,
GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_SET, -1, &update);
fail_unless (segment.stop == -1);
/* set some duration, stop -1 END seeks will now work with the
* duration, if the formats match */
gst_segment_set_duration (&segment, GST_FORMAT_BYTES, 200);
fail_unless (segment.duration == 200);
/* seek to end in any format with 0 should set the stop to the
* duration */
gst_segment_set_seek (&segment, 2.0,
GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_END, 0, &update);
fail_unless (segment.stop == 200);
fail_unless (segment.duration == 200);
/* subtract 100 from the end */
gst_segment_set_seek (&segment, 2.0,
GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_END, -100, &update);
fail_unless (segment.stop == 100);
fail_unless (segment.duration == 200);
/* add 100 to the duration, this should be clamped to the duration */
gst_segment_set_seek (&segment, 2.0,
GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_END, 100, &update);
fail_unless (segment.stop == 200);
fail_unless (segment.duration == 200);
/* add 300 to the start, this should be clamped to the duration */
gst_segment_set_seek (&segment, 2.0,
GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
GST_SEEK_TYPE_CUR, 300, GST_SEEK_TYPE_END, 0, &update);
fail_unless (segment.start == 200);
fail_unless (segment.stop == 200);
fail_unless (segment.duration == 200);
/* subtract 300 from the start, this should be clamped to 0 */
gst_segment_set_seek (&segment, 2.0,
GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE,
GST_SEEK_TYPE_CUR, -300, GST_SEEK_TYPE_END, 0, &update);
fail_unless (segment.start == 0);
fail_unless (segment.stop == 200);
fail_unless (segment.duration == 200);
}
GST_END_TEST;
/* mess with the segment structure in the bytes format */
GST_START_TEST (segment_newsegment_open)
{
@ -1505,6 +1636,7 @@ gst_segment_suite (void)
tcase_add_test (tc_chain, segment_seek_nosize);
tcase_add_test (tc_chain, segment_seek_size);
tcase_add_test (tc_chain, segment_seek_reverse);
tcase_add_test (tc_chain, segment_seek_rate);
tcase_add_test (tc_chain, segment_newsegment_open);
tcase_add_test (tc_chain, segment_newsegment_closed);
tcase_add_test (tc_chain, segment_newsegment_streamtime);