gst/base/gstbasesink.*: Handle newsegments more correctly.

Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_handle_object),
(gst_base_sink_event), (gst_base_sink_do_sync),
(gst_base_sink_handle_event):
* gst/base/gstbasesink.h:
Handle newsegments more correctly.

* gst/gstbus.c:
Fix docs.

* gst/gstevent.c: (gst_event_new_newsegment):
A newsegment cannot have a start_time of -1
This commit is contained in:
Wim Taymans 2005-09-01 18:12:18 +00:00
parent 1b028e6b03
commit 8099c34220
8 changed files with 294 additions and 113 deletions

View file

@ -1,3 +1,17 @@
2005-09-01 Wim Taymans <wim@fluendo.com>
* gst/base/gstbasesink.c: (gst_base_sink_handle_object),
(gst_base_sink_event), (gst_base_sink_do_sync),
(gst_base_sink_handle_event):
* gst/base/gstbasesink.h:
Handle newsegments more correctly.
* gst/gstbus.c:
Fix docs.
* gst/gstevent.c: (gst_event_new_newsegment):
A newsegment cannot have a start_time of -1
2005-09-01 Tim-Philipp Müller <tim at centricular dot net>
* win32/gstenumtypes.c:

2
common

@ -1 +1 @@
Subproject commit 74223ba3ec3be64622ac71d682b36c1f8f01350e
Subproject commit b0ee0e4262014001faceb47d71c3a44c75ab86b4

View file

@ -444,12 +444,15 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
case GST_EVENT_NEWSEGMENT:
{
GstFormat format;
gint64 segment_start;
gint64 segment_stop;
/* the newsegment event is needed to bring the buffer timestamps to the
* stream time and to drop samples outside of the playback segment. */
gst_event_parse_newsegment (event, &basesink->segment_rate, &format,
&basesink->segment_start, &basesink->segment_stop,
&basesink->segment_base);
&segment_start, &segment_stop, &basesink->segment_base);
basesink->have_newsegment = TRUE;
if (format != GST_FORMAT_TIME) {
GST_DEBUG_OBJECT (basesink,
@ -463,16 +466,40 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
basesink->segment_start = -1;
basesink->segment_stop = -1;
basesink->segment_base = -1;
} else {
GST_DEBUG_OBJECT (basesink,
"received DISCONT %" GST_TIME_FORMAT " -- %"
GST_TIME_FORMAT ", base %" GST_TIME_FORMAT,
GST_TIME_ARGS (basesink->segment_start),
GST_TIME_ARGS (basesink->segment_stop),
GST_TIME_ARGS (basesink->segment_base));
goto done_newsegment;
}
/* check if we really have a new segment or the previous one is
* closed */
if (basesink->segment_start != segment_start) {
/* the new segment has to be aligned with the old segment.
* We first update the accumulated time of the previous
* segment. the accumulated time is used when syncing to the
* clock. A flush event sets the accumulated time back to 0
*/
if (GST_CLOCK_TIME_IS_VALID (basesink->segment_stop)) {
basesink->segment_accum +=
basesink->segment_stop - basesink->segment_start;
} else if (GST_CLOCK_TIME_IS_VALID (basesink->current_end)) {
/* else use last seen timestamp as segment stop */
basesink->segment_accum +=
basesink->current_end - basesink->segment_start;
} else {
basesink->segment_accum = 0;
}
}
basesink->have_newsegment = TRUE;
basesink->segment_start = segment_start;
basesink->segment_stop = segment_stop;
GST_DEBUG_OBJECT (basesink,
"received DISCONT %" GST_TIME_FORMAT " -- %"
GST_TIME_FORMAT ", base %" GST_TIME_FORMAT ", accum %"
GST_TIME_FORMAT,
GST_TIME_ARGS (basesink->segment_start),
GST_TIME_ARGS (basesink->segment_stop),
GST_TIME_ARGS (basesink->segment_base),
GST_TIME_ARGS (basesink->segment_accum));
done_newsegment:
break;
}
default:
@ -784,6 +811,14 @@ gst_base_sink_event (GstPad * pad, GstEvent * event)
/* now we are completely unblocked and the _chain method
* will return */
GST_STREAM_LOCK (pad);
/* we need new segment info after the flush. */
basesink->segment_start = -1;
basesink->segment_stop = -1;
basesink->current_start = -1;
basesink->current_end = -1;
GST_DEBUG ("reset accum %" GST_TIME_FORMAT,
GST_TIME_ARGS (basesink->segment_accum));
basesink->segment_accum = 0;
GST_STREAM_UNLOCK (pad);
GST_DEBUG ("event unref %p %p", basesink, event);
@ -832,59 +867,99 @@ static gboolean
gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
{
gboolean result = TRUE;
GstClockTime start, end;
GstClockTimeDiff stream_start, stream_end;
GstBaseSinkClass *bclass;
gboolean start_valid, end_valid;
if (basesink->clock) {
GstClockTime start, end;
GstBaseSinkClass *bclass;
bclass = GST_BASE_SINK_GET_CLASS (basesink);
bclass = GST_BASE_SINK_GET_CLASS (basesink);
start = end = -1;
if (bclass->get_times)
bclass->get_times (basesink, buffer, &start, &end);
start = end = -1;
if (bclass->get_times)
bclass->get_times (basesink, buffer, &start, &end);
GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end));
start_valid = GST_CLOCK_TIME_IS_VALID (start);
end_valid = GST_CLOCK_TIME_IS_VALID (start);
if (GST_CLOCK_TIME_IS_VALID (start)) {
GstClockReturn ret;
GstClockTime base_time;
GstClockTimeDiff diff;
GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end));
/* bring timestamp to stream time using last segment offset. */
if ((diff = (gint64) start - basesink->segment_start) < 0)
goto too_late;
/* if we don't have a timestamp, we don't sync */
if (!start_valid)
goto done;
start = diff;
/* save last times seen. */
basesink->current_start = start;
if (end_valid)
basesink->current_end = end;
else
basesink->current_end = start;
GST_LOCK (basesink);
base_time = GST_ELEMENT (basesink)->base_time;
GST_LOG_OBJECT (basesink,
"waiting for clock, base time %" GST_TIME_FORMAT,
GST_TIME_ARGS (base_time));
/* save clock id so that we can unlock it if needed */
basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
start + base_time);
basesink->end_time = end;
GST_UNLOCK (basesink);
ret = gst_clock_id_wait (basesink->clock_id, NULL);
GST_LOCK (basesink);
if (basesink->clock_id) {
gst_clock_id_unref (basesink->clock_id);
basesink->clock_id = NULL;
}
GST_UNLOCK (basesink);
GST_LOG_OBJECT (basesink, "clock entry done: %d", ret);
if (ret == GST_CLOCK_UNSCHEDULED)
result = FALSE;
}
if (GST_CLOCK_TIME_IS_VALID (basesink->segment_stop)) {
/* check if not outside of the segment range, start is
* always valid here. */
if (start > basesink->segment_stop)
goto out_of_segment;
}
/* bring timestamp to stream time using last segment offset. */
if (GST_CLOCK_TIME_IS_VALID (basesink->segment_start)) {
/* check if not outside of the segment range */
if (end_valid && end < basesink->segment_start)
goto out_of_segment;
stream_start = (gint64) start - basesink->segment_start;
stream_end = (gint64) end - basesink->segment_start;
} else {
stream_start = (gint64) start;
stream_end = (gint64) end;
}
stream_start += basesink->segment_accum;
if (end_valid)
stream_end += basesink->segment_accum;
/* now do clocking */
if (basesink->clock) {
GstClockReturn ret;
GstClockTime base_time;
GST_LOCK (basesink);
base_time = GST_ELEMENT (basesink)->base_time;
GST_LOG_OBJECT (basesink,
"waiting for clock, base time %" GST_TIME_FORMAT,
GST_TIME_ARGS (base_time));
/* save clock id so that we can unlock it if needed */
basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
stream_start + base_time);
/* also save end_time of this buffer so that we can wait
* to signal EOS */
if (end_valid)
basesink->end_time = stream_end + base_time;
else
basesink->end_time = GST_CLOCK_TIME_NONE;
GST_UNLOCK (basesink);
ret = gst_clock_id_wait (basesink->clock_id, NULL);
GST_LOCK (basesink);
if (basesink->clock_id) {
gst_clock_id_unref (basesink->clock_id);
basesink->clock_id = NULL;
}
GST_UNLOCK (basesink);
GST_LOG_OBJECT (basesink, "clock entry done: %d", ret);
if (ret == GST_CLOCK_UNSCHEDULED)
result = FALSE;
}
done:
return result;
too_late:
out_of_segment:
{
GST_LOG_OBJECT (basesink, "buffer skipped, not in segment");
return FALSE;
@ -910,7 +985,7 @@ gst_base_sink_handle_event (GstBaseSink * basesink, GstEvent * event)
/* wait for last buffer to finish if we have a valid end time */
if (GST_CLOCK_TIME_IS_VALID (basesink->end_time)) {
basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
basesink->end_time + GST_ELEMENT (basesink)->base_time);
basesink->end_time);
GST_UNLOCK (basesink);
gst_clock_id_wait (basesink->clock_id, NULL);

View file

@ -82,6 +82,11 @@ struct _GstBaseSink {
gint64 segment_start;
gint64 segment_stop;
gint64 segment_base;
gint64 segment_accum;
gint64 current_start;
gint64 current_duration;
gint64 current_end;
/*< private >*/ /* with LOCK */
GstClock *clock;

View file

@ -411,7 +411,7 @@ gst_bus_pop (GstBus * bus)
* @bus: a #GstBus
*
* Peek the message on the top of the bus' queue. The message will remain
* on the bus' message queue. A reference is returned, and needs to be freed
* on the bus' message queue. A reference is returned, and needs to be unreffed
* by the caller.
*
* Returns: The #GstMessage that is on the bus, or NULL if the bus is empty.

View file

@ -286,11 +286,16 @@ gst_event_new_eos (void)
* Allocate a new newsegment event with the given format/values tripplets.
*
* The newsegment event marks the range of buffers to be processed. All
* data not within the segment range is not to be processed.
* data not within the segment range is not to be processed. This can be
* used intelligently by plugins to use more efficient methods of skipping
* unneeded packets.
*
* The base time of the segment is used to convert the buffer timestamps
* The base time of the segment is also used to convert the buffer timestamps
* into the stream time again.
*
* The @start_value cannot be -1, the @stop_value can be -1. If there
* is a valid @stop_value given, it must be smaller than @start_value.
*
* After a newsegment event, the buffer stream time is calculated with:
*
* TIMESTAMP(buf) - start_time + base
@ -314,8 +319,10 @@ gst_event_new_newsegment (gdouble rate, GstFormat format,
"start %lld, stop %lld, base %lld",
rate, format, start_value, stop_value, base);
}
if (start_value == -1)
g_return_val_if_fail (start_value != -1, NULL);
if (start_value != -1 && stop_value != -1)
if (stop_value != -1)
g_return_val_if_fail (start_value < stop_value, NULL);
return gst_event_new_custom (GST_EVENT_NEWSEGMENT,

View file

@ -444,12 +444,15 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
case GST_EVENT_NEWSEGMENT:
{
GstFormat format;
gint64 segment_start;
gint64 segment_stop;
/* the newsegment event is needed to bring the buffer timestamps to the
* stream time and to drop samples outside of the playback segment. */
gst_event_parse_newsegment (event, &basesink->segment_rate, &format,
&basesink->segment_start, &basesink->segment_stop,
&basesink->segment_base);
&segment_start, &segment_stop, &basesink->segment_base);
basesink->have_newsegment = TRUE;
if (format != GST_FORMAT_TIME) {
GST_DEBUG_OBJECT (basesink,
@ -463,16 +466,40 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
basesink->segment_start = -1;
basesink->segment_stop = -1;
basesink->segment_base = -1;
} else {
GST_DEBUG_OBJECT (basesink,
"received DISCONT %" GST_TIME_FORMAT " -- %"
GST_TIME_FORMAT ", base %" GST_TIME_FORMAT,
GST_TIME_ARGS (basesink->segment_start),
GST_TIME_ARGS (basesink->segment_stop),
GST_TIME_ARGS (basesink->segment_base));
goto done_newsegment;
}
/* check if we really have a new segment or the previous one is
* closed */
if (basesink->segment_start != segment_start) {
/* the new segment has to be aligned with the old segment.
* We first update the accumulated time of the previous
* segment. the accumulated time is used when syncing to the
* clock. A flush event sets the accumulated time back to 0
*/
if (GST_CLOCK_TIME_IS_VALID (basesink->segment_stop)) {
basesink->segment_accum +=
basesink->segment_stop - basesink->segment_start;
} else if (GST_CLOCK_TIME_IS_VALID (basesink->current_end)) {
/* else use last seen timestamp as segment stop */
basesink->segment_accum +=
basesink->current_end - basesink->segment_start;
} else {
basesink->segment_accum = 0;
}
}
basesink->have_newsegment = TRUE;
basesink->segment_start = segment_start;
basesink->segment_stop = segment_stop;
GST_DEBUG_OBJECT (basesink,
"received DISCONT %" GST_TIME_FORMAT " -- %"
GST_TIME_FORMAT ", base %" GST_TIME_FORMAT ", accum %"
GST_TIME_FORMAT,
GST_TIME_ARGS (basesink->segment_start),
GST_TIME_ARGS (basesink->segment_stop),
GST_TIME_ARGS (basesink->segment_base),
GST_TIME_ARGS (basesink->segment_accum));
done_newsegment:
break;
}
default:
@ -784,6 +811,14 @@ gst_base_sink_event (GstPad * pad, GstEvent * event)
/* now we are completely unblocked and the _chain method
* will return */
GST_STREAM_LOCK (pad);
/* we need new segment info after the flush. */
basesink->segment_start = -1;
basesink->segment_stop = -1;
basesink->current_start = -1;
basesink->current_end = -1;
GST_DEBUG ("reset accum %" GST_TIME_FORMAT,
GST_TIME_ARGS (basesink->segment_accum));
basesink->segment_accum = 0;
GST_STREAM_UNLOCK (pad);
GST_DEBUG ("event unref %p %p", basesink, event);
@ -832,59 +867,99 @@ static gboolean
gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
{
gboolean result = TRUE;
GstClockTime start, end;
GstClockTimeDiff stream_start, stream_end;
GstBaseSinkClass *bclass;
gboolean start_valid, end_valid;
if (basesink->clock) {
GstClockTime start, end;
GstBaseSinkClass *bclass;
bclass = GST_BASE_SINK_GET_CLASS (basesink);
bclass = GST_BASE_SINK_GET_CLASS (basesink);
start = end = -1;
if (bclass->get_times)
bclass->get_times (basesink, buffer, &start, &end);
start = end = -1;
if (bclass->get_times)
bclass->get_times (basesink, buffer, &start, &end);
GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end));
start_valid = GST_CLOCK_TIME_IS_VALID (start);
end_valid = GST_CLOCK_TIME_IS_VALID (start);
if (GST_CLOCK_TIME_IS_VALID (start)) {
GstClockReturn ret;
GstClockTime base_time;
GstClockTimeDiff diff;
GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end));
/* bring timestamp to stream time using last segment offset. */
if ((diff = (gint64) start - basesink->segment_start) < 0)
goto too_late;
/* if we don't have a timestamp, we don't sync */
if (!start_valid)
goto done;
start = diff;
/* save last times seen. */
basesink->current_start = start;
if (end_valid)
basesink->current_end = end;
else
basesink->current_end = start;
GST_LOCK (basesink);
base_time = GST_ELEMENT (basesink)->base_time;
GST_LOG_OBJECT (basesink,
"waiting for clock, base time %" GST_TIME_FORMAT,
GST_TIME_ARGS (base_time));
/* save clock id so that we can unlock it if needed */
basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
start + base_time);
basesink->end_time = end;
GST_UNLOCK (basesink);
ret = gst_clock_id_wait (basesink->clock_id, NULL);
GST_LOCK (basesink);
if (basesink->clock_id) {
gst_clock_id_unref (basesink->clock_id);
basesink->clock_id = NULL;
}
GST_UNLOCK (basesink);
GST_LOG_OBJECT (basesink, "clock entry done: %d", ret);
if (ret == GST_CLOCK_UNSCHEDULED)
result = FALSE;
}
if (GST_CLOCK_TIME_IS_VALID (basesink->segment_stop)) {
/* check if not outside of the segment range, start is
* always valid here. */
if (start > basesink->segment_stop)
goto out_of_segment;
}
/* bring timestamp to stream time using last segment offset. */
if (GST_CLOCK_TIME_IS_VALID (basesink->segment_start)) {
/* check if not outside of the segment range */
if (end_valid && end < basesink->segment_start)
goto out_of_segment;
stream_start = (gint64) start - basesink->segment_start;
stream_end = (gint64) end - basesink->segment_start;
} else {
stream_start = (gint64) start;
stream_end = (gint64) end;
}
stream_start += basesink->segment_accum;
if (end_valid)
stream_end += basesink->segment_accum;
/* now do clocking */
if (basesink->clock) {
GstClockReturn ret;
GstClockTime base_time;
GST_LOCK (basesink);
base_time = GST_ELEMENT (basesink)->base_time;
GST_LOG_OBJECT (basesink,
"waiting for clock, base time %" GST_TIME_FORMAT,
GST_TIME_ARGS (base_time));
/* save clock id so that we can unlock it if needed */
basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
stream_start + base_time);
/* also save end_time of this buffer so that we can wait
* to signal EOS */
if (end_valid)
basesink->end_time = stream_end + base_time;
else
basesink->end_time = GST_CLOCK_TIME_NONE;
GST_UNLOCK (basesink);
ret = gst_clock_id_wait (basesink->clock_id, NULL);
GST_LOCK (basesink);
if (basesink->clock_id) {
gst_clock_id_unref (basesink->clock_id);
basesink->clock_id = NULL;
}
GST_UNLOCK (basesink);
GST_LOG_OBJECT (basesink, "clock entry done: %d", ret);
if (ret == GST_CLOCK_UNSCHEDULED)
result = FALSE;
}
done:
return result;
too_late:
out_of_segment:
{
GST_LOG_OBJECT (basesink, "buffer skipped, not in segment");
return FALSE;
@ -910,7 +985,7 @@ gst_base_sink_handle_event (GstBaseSink * basesink, GstEvent * event)
/* wait for last buffer to finish if we have a valid end time */
if (GST_CLOCK_TIME_IS_VALID (basesink->end_time)) {
basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
basesink->end_time + GST_ELEMENT (basesink)->base_time);
basesink->end_time);
GST_UNLOCK (basesink);
gst_clock_id_wait (basesink->clock_id, NULL);

View file

@ -82,6 +82,11 @@ struct _GstBaseSink {
gint64 segment_start;
gint64 segment_stop;
gint64 segment_base;
gint64 segment_accum;
gint64 current_start;
gint64 current_duration;
gint64 current_end;
/*< private >*/ /* with LOCK */
GstClock *clock;