+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:
-Subproject commit 74223ba3ec3be64622ac71d682b36c1f8f01350e
+Subproject commit b0ee0e4262014001faceb47d71c3a44c75ab86b4
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,
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:
/* 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);
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));
+
+ /* if we don't have a timestamp, we don't sync */
+ if (!start_valid)
+ goto done;
- /* bring timestamp to stream time using last segment offset. */
- if ((diff = (gint64) start - basesink->segment_start) < 0)
- goto too_late;
+ /* save last times seen. */
+ basesink->current_start = start;
+ if (end_valid)
+ basesink->current_end = end;
+ else
+ basesink->current_end = start;
- start = diff;
+ 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;
+ }
- 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);
+ /* 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;
- ret = gst_clock_id_wait (basesink->clock_id, NULL);
+ stream_start = (gint64) start - basesink->segment_start;
+ stream_end = (gint64) end - basesink->segment_start;
+ } else {
+ stream_start = (gint64) start;
+ stream_end = (gint64) end;
+ }
- GST_LOCK (basesink);
- if (basesink->clock_id) {
- gst_clock_id_unref (basesink->clock_id);
- basesink->clock_id = NULL;
- }
- GST_UNLOCK (basesink);
+ stream_start += basesink->segment_accum;
+ if (end_valid)
+ stream_end += basesink->segment_accum;
- GST_LOG_OBJECT (basesink, "clock entry done: %d", ret);
- if (ret == GST_CLOCK_UNSCHEDULED)
- result = FALSE;
+ /* 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;
/* 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);
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;
* @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.
* 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
"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,
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,
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:
/* 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);
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));
+
+ /* if we don't have a timestamp, we don't sync */
+ if (!start_valid)
+ goto done;
- /* bring timestamp to stream time using last segment offset. */
- if ((diff = (gint64) start - basesink->segment_start) < 0)
- goto too_late;
+ /* save last times seen. */
+ basesink->current_start = start;
+ if (end_valid)
+ basesink->current_end = end;
+ else
+ basesink->current_end = start;
- start = diff;
+ 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;
+ }
- 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);
+ /* 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;
- ret = gst_clock_id_wait (basesink->clock_id, NULL);
+ stream_start = (gint64) start - basesink->segment_start;
+ stream_end = (gint64) end - basesink->segment_start;
+ } else {
+ stream_start = (gint64) start;
+ stream_end = (gint64) end;
+ }
- GST_LOCK (basesink);
- if (basesink->clock_id) {
- gst_clock_id_unref (basesink->clock_id);
- basesink->clock_id = NULL;
- }
- GST_UNLOCK (basesink);
+ stream_start += basesink->segment_accum;
+ if (end_valid)
+ stream_end += basesink->segment_accum;
- GST_LOG_OBJECT (basesink, "clock entry done: %d", ret);
- if (ret == GST_CLOCK_UNSCHEDULED)
- result = FALSE;
+ /* 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;
/* 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);
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;