gst/base/gstbasesink.*: Handle newsegment events correctly.

Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_handle_object),
(gst_base_sink_get_times), (gst_base_sink_do_sync),
(gst_base_sink_handle_buffer), (gst_base_sink_change_state):
* gst/base/gstbasesink.h:
Handle newsegment events correctly.
Drop buffers out of the segment range.
This commit is contained in:
Wim Taymans 2005-08-24 17:57:36 +00:00
parent 73bcaf6318
commit ec8ec3da8a
5 changed files with 217 additions and 90 deletions

View file

@ -1,3 +1,12 @@
2005-08-24 Wim Taymans <wim@fluendo.com>
* gst/base/gstbasesink.c: (gst_base_sink_handle_object),
(gst_base_sink_get_times), (gst_base_sink_do_sync),
(gst_base_sink_handle_buffer), (gst_base_sink_change_state):
* gst/base/gstbasesink.h:
Handle newsegment events correctly.
Drop buffers out of the segment range.
2005-08-22 Andy Wingo <wingo@pobox.com>
* gst/gstutils.h (GST_BOILERPLATE_WITH_INTERFACE): New ghetto

View file

@ -488,23 +488,33 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
case GST_EVENT_NEWSEGMENT:
{
GstFormat format;
gdouble rate;
/* the newsegment event is needed to bring the buffer timestamps to the
* stream time */
gst_event_parse_newsegment (event, &rate, &format,
&basesink->discont_start, &basesink->discont_stop, NULL);
* 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);
if (format != GST_FORMAT_TIME) {
/* this means this sink will not be able to sync to the clock */
basesink->discont_start = 0;
basesink->discont_stop = 0;
}
basesink->have_discont = TRUE;
GST_DEBUG ("received non time %d DISCONT %" G_GINT64_FORMAT
" -- %" G_GINT64_FORMAT ", base %" G_GINT64_FORMAT,
format, basesink->segment_start, basesink->segment_stop,
basesink->segment_base);
/* this means this sink will not be able to clip or drop samples
* and timestamps have to start from 0. */
basesink->segment_start = -1;
basesink->segment_stop = -1;
basesink->segment_base = -1;
} else {
GST_DEBUG ("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));
}
basesink->have_newsegment = TRUE;
GST_DEBUG ("received DISCONT %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
GST_TIME_ARGS (basesink->discont_start),
GST_TIME_ARGS (basesink->discont_stop));
break;
}
default:
@ -512,14 +522,43 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
}
basesink->events_queued++;
} else {
if (!basesink->have_discont) {
GstBuffer *buf = GST_BUFFER (obj);
if (!basesink->have_newsegment) {
GST_ELEMENT_ERROR (basesink, STREAM, STOPPED,
("Received buffer without a new-segment. Cannot sync to clock."),
("Received buffer without a new-segment. Cannot sync to clock."));
basesink->have_discont = TRUE;
basesink->have_newsegment = TRUE;
/* this means this sink will not be able to sync to the clock */
basesink->discont_start = 0;
basesink->discont_stop = 0;
basesink->segment_start = 0;
basesink->segment_stop = 0;
}
/* check if the buffer needs to be dropped */
if (TRUE) {
GstClockTime start = -1, end = -1;
/* we don't use the subclassed method as it may not return
* valid values for our purpose here */
gst_base_sink_get_times (basesink, buf, &start, &end);
GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start),
GST_TIME_ARGS (end));
/* need to drop if the timestamp is not between segment_start and
* segment_stop. we check if the complete sample is outside of the
* range since the sink might be able to clip the sample. */
if (GST_CLOCK_TIME_IS_VALID (end) &&
GST_CLOCK_TIME_IS_VALID (basesink->segment_start)) {
if (end <= basesink->segment_start)
goto dropping;
}
if (GST_CLOCK_TIME_IS_VALID (start) &&
GST_CLOCK_TIME_IS_VALID (basesink->segment_stop)) {
if (basesink->segment_stop <= start)
goto dropping;
}
}
basesink->preroll_queued++;
basesink->buffers_queued++;
@ -630,6 +669,20 @@ no_preroll:
return ret;
}
dropping:
{
GstBuffer *buf;
buf = GST_BUFFER (g_queue_pop_tail (basesink->preroll_queue));
GST_DEBUG ("dropping sample outside of segment boundaries %"
GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
gst_buffer_unref (buf);
GST_PREROLL_UNLOCK (pad);
return GST_FLOW_OK;
}
playing_async:
{
GstFlowReturn ret;
@ -793,26 +846,13 @@ gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
timestamp = GST_BUFFER_TIMESTAMP (buffer);
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
GstClockTimeDiff diff;
/* bring timestamp to stream time using last
* discont offset. */
if ((diff = timestamp - basesink->discont_start) < 0)
goto too_late;
/* get duration to calculate end time */
duration = GST_BUFFER_DURATION (buffer);
if (GST_CLOCK_TIME_IS_VALID (duration)) {
*end = diff + duration;
*end = timestamp + duration;
}
*start = diff;
}
return;
too_late:
{
*start = GST_CLOCK_TIME_NONE;
*end = GST_CLOCK_TIME_NONE;
*start = timestamp;
}
}
@ -845,6 +885,13 @@ gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
if (GST_CLOCK_TIME_IS_VALID (start)) {
GstClockReturn ret;
GstClockTime base_time;
GstClockTimeDiff diff;
/* bring timestamp to stream time using last segment offset. */
if ((diff = (gint64) start - basesink->segment_start) < 0)
goto too_late;
start = diff;
GST_LOCK (basesink);
base_time = GST_ELEMENT (basesink)->base_time;
@ -873,6 +920,12 @@ gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
}
}
return result;
too_late:
{
GST_LOG_OBJECT (basesink, "buffer skipped, not in segment");
return FALSE;
}
}
@ -950,16 +1003,18 @@ gst_base_sink_handle_event (GstBaseSink * basesink, GstEvent * event)
static inline GstFlowReturn
gst_base_sink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf)
{
GstBaseSinkClass *bclass;
GstFlowReturn ret;
GstFlowReturn ret = GST_FLOW_OK;
gboolean render;
gst_base_sink_do_sync (basesink, buf);
render = gst_base_sink_do_sync (basesink, buf);
bclass = GST_BASE_SINK_GET_CLASS (basesink);
if (bclass->render)
ret = bclass->render (basesink, buf);
else
ret = GST_FLOW_OK;
if (render) {
GstBaseSinkClass *bclass;
bclass = GST_BASE_SINK_GET_CLASS (basesink);
if (bclass->render)
ret = bclass->render (basesink, buf);
}
GST_DEBUG ("buffer unref after render %p", basesink, buf);
gst_buffer_unref (buf);
@ -1119,9 +1174,10 @@ gst_base_sink_change_state (GstElement * element)
basesink->have_preroll = FALSE;
basesink->need_preroll = TRUE;
GST_PREROLL_UNLOCK (basesink->sinkpad);
basesink->have_discont = FALSE;
basesink->discont_start = 0;
basesink->discont_stop = 0;
basesink->have_newsegment = FALSE;
basesink->segment_rate = 1.0;
basesink->segment_start = 0;
basesink->segment_stop = 0;
ret = GST_STATE_ASYNC;
break;
case GST_STATE_PAUSED_TO_PLAYING:

View file

@ -74,9 +74,12 @@ struct _GstBaseSink {
GstClockID clock_id;
GstClockTime end_time;
gboolean have_discont;
GstClockTimeDiff discont_start;
GstClockTimeDiff discont_stop;
gboolean have_newsegment;
gdouble segment_rate;
gint64 segment_start;
gint64 segment_stop;
gint64 segment_base;
gboolean eos;
gboolean need_preroll;

View file

@ -488,23 +488,33 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
case GST_EVENT_NEWSEGMENT:
{
GstFormat format;
gdouble rate;
/* the newsegment event is needed to bring the buffer timestamps to the
* stream time */
gst_event_parse_newsegment (event, &rate, &format,
&basesink->discont_start, &basesink->discont_stop, NULL);
* 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);
if (format != GST_FORMAT_TIME) {
/* this means this sink will not be able to sync to the clock */
basesink->discont_start = 0;
basesink->discont_stop = 0;
}
basesink->have_discont = TRUE;
GST_DEBUG ("received non time %d DISCONT %" G_GINT64_FORMAT
" -- %" G_GINT64_FORMAT ", base %" G_GINT64_FORMAT,
format, basesink->segment_start, basesink->segment_stop,
basesink->segment_base);
/* this means this sink will not be able to clip or drop samples
* and timestamps have to start from 0. */
basesink->segment_start = -1;
basesink->segment_stop = -1;
basesink->segment_base = -1;
} else {
GST_DEBUG ("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));
}
basesink->have_newsegment = TRUE;
GST_DEBUG ("received DISCONT %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
GST_TIME_ARGS (basesink->discont_start),
GST_TIME_ARGS (basesink->discont_stop));
break;
}
default:
@ -512,14 +522,43 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
}
basesink->events_queued++;
} else {
if (!basesink->have_discont) {
GstBuffer *buf = GST_BUFFER (obj);
if (!basesink->have_newsegment) {
GST_ELEMENT_ERROR (basesink, STREAM, STOPPED,
("Received buffer without a new-segment. Cannot sync to clock."),
("Received buffer without a new-segment. Cannot sync to clock."));
basesink->have_discont = TRUE;
basesink->have_newsegment = TRUE;
/* this means this sink will not be able to sync to the clock */
basesink->discont_start = 0;
basesink->discont_stop = 0;
basesink->segment_start = 0;
basesink->segment_stop = 0;
}
/* check if the buffer needs to be dropped */
if (TRUE) {
GstClockTime start = -1, end = -1;
/* we don't use the subclassed method as it may not return
* valid values for our purpose here */
gst_base_sink_get_times (basesink, buf, &start, &end);
GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start),
GST_TIME_ARGS (end));
/* need to drop if the timestamp is not between segment_start and
* segment_stop. we check if the complete sample is outside of the
* range since the sink might be able to clip the sample. */
if (GST_CLOCK_TIME_IS_VALID (end) &&
GST_CLOCK_TIME_IS_VALID (basesink->segment_start)) {
if (end <= basesink->segment_start)
goto dropping;
}
if (GST_CLOCK_TIME_IS_VALID (start) &&
GST_CLOCK_TIME_IS_VALID (basesink->segment_stop)) {
if (basesink->segment_stop <= start)
goto dropping;
}
}
basesink->preroll_queued++;
basesink->buffers_queued++;
@ -630,6 +669,20 @@ no_preroll:
return ret;
}
dropping:
{
GstBuffer *buf;
buf = GST_BUFFER (g_queue_pop_tail (basesink->preroll_queue));
GST_DEBUG ("dropping sample outside of segment boundaries %"
GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
gst_buffer_unref (buf);
GST_PREROLL_UNLOCK (pad);
return GST_FLOW_OK;
}
playing_async:
{
GstFlowReturn ret;
@ -793,26 +846,13 @@ gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
timestamp = GST_BUFFER_TIMESTAMP (buffer);
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
GstClockTimeDiff diff;
/* bring timestamp to stream time using last
* discont offset. */
if ((diff = timestamp - basesink->discont_start) < 0)
goto too_late;
/* get duration to calculate end time */
duration = GST_BUFFER_DURATION (buffer);
if (GST_CLOCK_TIME_IS_VALID (duration)) {
*end = diff + duration;
*end = timestamp + duration;
}
*start = diff;
}
return;
too_late:
{
*start = GST_CLOCK_TIME_NONE;
*end = GST_CLOCK_TIME_NONE;
*start = timestamp;
}
}
@ -845,6 +885,13 @@ gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
if (GST_CLOCK_TIME_IS_VALID (start)) {
GstClockReturn ret;
GstClockTime base_time;
GstClockTimeDiff diff;
/* bring timestamp to stream time using last segment offset. */
if ((diff = (gint64) start - basesink->segment_start) < 0)
goto too_late;
start = diff;
GST_LOCK (basesink);
base_time = GST_ELEMENT (basesink)->base_time;
@ -873,6 +920,12 @@ gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
}
}
return result;
too_late:
{
GST_LOG_OBJECT (basesink, "buffer skipped, not in segment");
return FALSE;
}
}
@ -950,16 +1003,18 @@ gst_base_sink_handle_event (GstBaseSink * basesink, GstEvent * event)
static inline GstFlowReturn
gst_base_sink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf)
{
GstBaseSinkClass *bclass;
GstFlowReturn ret;
GstFlowReturn ret = GST_FLOW_OK;
gboolean render;
gst_base_sink_do_sync (basesink, buf);
render = gst_base_sink_do_sync (basesink, buf);
bclass = GST_BASE_SINK_GET_CLASS (basesink);
if (bclass->render)
ret = bclass->render (basesink, buf);
else
ret = GST_FLOW_OK;
if (render) {
GstBaseSinkClass *bclass;
bclass = GST_BASE_SINK_GET_CLASS (basesink);
if (bclass->render)
ret = bclass->render (basesink, buf);
}
GST_DEBUG ("buffer unref after render %p", basesink, buf);
gst_buffer_unref (buf);
@ -1119,9 +1174,10 @@ gst_base_sink_change_state (GstElement * element)
basesink->have_preroll = FALSE;
basesink->need_preroll = TRUE;
GST_PREROLL_UNLOCK (basesink->sinkpad);
basesink->have_discont = FALSE;
basesink->discont_start = 0;
basesink->discont_stop = 0;
basesink->have_newsegment = FALSE;
basesink->segment_rate = 1.0;
basesink->segment_start = 0;
basesink->segment_stop = 0;
ret = GST_STATE_ASYNC;
break;
case GST_STATE_PAUSED_TO_PLAYING:

View file

@ -74,9 +74,12 @@ struct _GstBaseSink {
GstClockID clock_id;
GstClockTime end_time;
gboolean have_discont;
GstClockTimeDiff discont_start;
GstClockTimeDiff discont_stop;
gboolean have_newsegment;
gdouble segment_rate;
gint64 segment_start;
gint64 segment_stop;
gint64 segment_base;
gboolean eos;
gboolean need_preroll;