mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-22 16:26:39 +00:00
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:
parent
3c718ae9f4
commit
a332964e6c
5 changed files with 184 additions and 21 deletions
17
ChangeLog
17
ChangeLog
|
@ -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>
|
2007-12-18 Sebastian Dröge <slomo@circular-chaos.org>
|
||||||
|
|
||||||
Patch by: Matthias Bolte <photon at mail dot upb dot de>
|
Patch by: Matthias Bolte <photon at mail dot upb dot de>
|
||||||
|
|
2
common
2
common
|
@ -1 +1 @@
|
||||||
Subproject commit 67b8f4e3c576945f4d778c9040876af3a5a0756e
|
Subproject commit 970759077c95ee4e85650db023ac6f974e2aa5e1
|
|
@ -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
|
perform synchronisation. Indeed, the running time can be observed in each
|
||||||
element (during the PLAYING state) as:
|
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
|
Timestamps
|
||||||
----------
|
----------
|
||||||
|
|
||||||
The GstBuffer timestamps and the preceeding NEW_SEGMENT event (See
|
The GstBuffer timestamps and the preceeding NEW_SEGMENT event (See
|
||||||
part-streams.txt) define a transformation of the buffers to running_time as
|
part-streams.txt) define a transformation of the buffer timestamps to
|
||||||
follows:
|
running_time as follows:
|
||||||
|
|
||||||
The following notation is used:
|
The following notation is used:
|
||||||
|
|
||||||
|
@ -76,6 +79,7 @@ The following notation is used:
|
||||||
|
|
||||||
NS: NEWSEGMENT event preceeding the buffers.
|
NS: NEWSEGMENT event preceeding the buffers.
|
||||||
- NS.start: start field in the NEWSEGMENT event
|
- NS.start: start field in the NEWSEGMENT event
|
||||||
|
- NS.stop: stop field in the NEWSEGMENT event
|
||||||
- NS.rate: rate field of NEWSEGMENT event
|
- NS.rate: rate field of NEWSEGMENT event
|
||||||
- NS.abs_rate: absolute value of rate field of NEWSEGMENT event
|
- NS.abs_rate: absolute value of rate field of NEWSEGMENT event
|
||||||
- NS.time: time field in the 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:
|
The following transformation to running_time exist:
|
||||||
|
|
||||||
if (NS.rate > 0.0)
|
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
|
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 ==
|
The first displayable buffer will yield a value of 0 (since B.timestamp ==
|
||||||
NS.start and NS.accum == 0).
|
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.
|
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
|
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).
|
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
|
We prefix C. and B. before the two running times to note how they were
|
||||||
calculated.
|
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.
|
B.running_time at the moment when the clock reaches the same C.running_time.
|
||||||
|
|
||||||
Thus the following must hold:
|
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:
|
It is the stream time that is used for:
|
||||||
|
|
||||||
- report the POSITION query in the pipeline
|
- 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
|
- the position used to synchronize controller values
|
||||||
|
|
||||||
Stream time is calculated using the buffer times and the preceeding NEWSEGMENT
|
Stream time is calculated using the buffer times and the preceeding NEWSEGMENT
|
||||||
|
|
|
@ -274,15 +274,13 @@ gst_segment_set_seek (GstSegment * segment, gdouble rate,
|
||||||
|
|
||||||
if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED))
|
if (G_UNLIKELY (segment->format == GST_FORMAT_UNDEFINED))
|
||||||
segment->format = format;
|
segment->format = format;
|
||||||
else
|
|
||||||
g_return_if_fail (segment->format == format);
|
|
||||||
|
|
||||||
update_start = update_stop = TRUE;
|
update_start = update_stop = TRUE;
|
||||||
|
|
||||||
/* start is never invalid */
|
/* segment->start is never invalid */
|
||||||
switch (start_type) {
|
switch (start_type) {
|
||||||
case GST_SEEK_TYPE_NONE:
|
case GST_SEEK_TYPE_NONE:
|
||||||
/* no update to segment */
|
/* no update to segment, take previous start */
|
||||||
start = segment->start;
|
start = segment->start;
|
||||||
update_start = FALSE;
|
update_start = FALSE;
|
||||||
break;
|
break;
|
||||||
|
@ -290,13 +288,17 @@ gst_segment_set_seek (GstSegment * segment, gdouble rate,
|
||||||
/* start holds desired position, map -1 to the start */
|
/* start holds desired position, map -1 to the start */
|
||||||
if (start == -1)
|
if (start == -1)
|
||||||
start = 0;
|
start = 0;
|
||||||
|
/* start must be 0 or the formats must match */
|
||||||
|
g_return_if_fail (start == 0 || segment->format == format);
|
||||||
break;
|
break;
|
||||||
case GST_SEEK_TYPE_CUR:
|
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;
|
start = segment->start + start;
|
||||||
break;
|
break;
|
||||||
case GST_SEEK_TYPE_END:
|
case GST_SEEK_TYPE_END:
|
||||||
if (segment->duration != -1) {
|
if (segment->duration != -1) {
|
||||||
|
g_return_if_fail (start == 0 || segment->format == format);
|
||||||
/* add start to total length */
|
/* add start to total length */
|
||||||
start = segment->duration + start;
|
start = segment->duration + start;
|
||||||
} else {
|
} else {
|
||||||
|
@ -319,18 +321,24 @@ gst_segment_set_seek (GstSegment * segment, gdouble rate,
|
||||||
update_stop = FALSE;
|
update_stop = FALSE;
|
||||||
break;
|
break;
|
||||||
case GST_SEEK_TYPE_SET:
|
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;
|
break;
|
||||||
case GST_SEEK_TYPE_CUR:
|
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;
|
stop = segment->stop + stop;
|
||||||
else
|
} else
|
||||||
stop = -1;
|
stop = -1;
|
||||||
break;
|
break;
|
||||||
case GST_SEEK_TYPE_END:
|
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;
|
stop = segment->duration + stop;
|
||||||
else {
|
} else {
|
||||||
stop = segment->stop;
|
stop = segment->stop;
|
||||||
update_stop = FALSE;
|
update_stop = FALSE;
|
||||||
}
|
}
|
||||||
|
@ -373,7 +381,6 @@ gst_segment_set_seek (GstSegment * segment, gdouble rate,
|
||||||
*update = last_stop != segment->last_stop;
|
*update = last_stop != segment->last_stop;
|
||||||
|
|
||||||
/* update new position */
|
/* update new position */
|
||||||
if (last_stop != segment->last_stop)
|
|
||||||
segment->last_stop = last_stop;
|
segment->last_stop = last_stop;
|
||||||
|
|
||||||
segment->time = start;
|
segment->time = start;
|
||||||
|
|
|
@ -435,6 +435,137 @@ GST_START_TEST (segment_seek_reverse)
|
||||||
|
|
||||||
GST_END_TEST;
|
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 */
|
/* mess with the segment structure in the bytes format */
|
||||||
GST_START_TEST (segment_newsegment_open)
|
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_nosize);
|
||||||
tcase_add_test (tc_chain, segment_seek_size);
|
tcase_add_test (tc_chain, segment_seek_size);
|
||||||
tcase_add_test (tc_chain, segment_seek_reverse);
|
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_open);
|
||||||
tcase_add_test (tc_chain, segment_newsegment_closed);
|
tcase_add_test (tc_chain, segment_newsegment_closed);
|
||||||
tcase_add_test (tc_chain, segment_newsegment_streamtime);
|
tcase_add_test (tc_chain, segment_newsegment_streamtime);
|
||||||
|
|
Loading…
Reference in a new issue