From d80f874fc8f1c3c3dd84bf84fc0d47c358454e66 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 8 Oct 2005 09:58:30 +0000 Subject: [PATCH] gst/base/gstbasesink.*: Repost EOS message while going to PLAYING if still EOS. Original commit message from CVS: * gst/base/gstbasesink.c: (gst_base_sink_preroll_queue_flush), (gst_base_sink_handle_object), (gst_base_sink_event), (gst_base_sink_wait), (gst_base_sink_handle_event), (gst_base_sink_change_state): * gst/base/gstbasesink.h: Repost EOS message while going to PLAYING if still EOS. Make sure that when receiving a FLUSH_START we don't attempt to sync on the clock anymore. --- ChangeLog | 11 +++++++ gst/base/gstbasesink.c | 57 ++++++++++++++++++++++++++++--------- gst/base/gstbasesink.h | 2 ++ libs/gst/base/gstbasesink.c | 57 ++++++++++++++++++++++++++++--------- libs/gst/base/gstbasesink.h | 2 ++ 5 files changed, 103 insertions(+), 26 deletions(-) diff --git a/ChangeLog b/ChangeLog index a4524752ce..a1b704902e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2005-10-08 Wim Taymans + + * gst/base/gstbasesink.c: (gst_base_sink_preroll_queue_flush), + (gst_base_sink_handle_object), (gst_base_sink_event), + (gst_base_sink_wait), (gst_base_sink_handle_event), + (gst_base_sink_change_state): + * gst/base/gstbasesink.h: + Repost EOS message while going to PLAYING if still EOS. + Make sure that when receiving a FLUSH_START we don't attempt + to sync on the clock anymore. + 2005-10-08 Wim Taymans * tools/gst-launch.c: (event_loop): diff --git a/gst/base/gstbasesink.c b/gst/base/gstbasesink.c index d2fc8c5add..f70e66aaf8 100644 --- a/gst/base/gstbasesink.c +++ b/gst/base/gstbasesink.c @@ -432,6 +432,7 @@ gst_base_sink_preroll_queue_flush (GstBaseSink * basesink, GstPad * pad) } /* we can't have EOS anymore now */ basesink->eos = FALSE; + basesink->eos_queued = FALSE; basesink->preroll_queued = 0; basesink->buffers_queued = 0; basesink->events_queued = 0; @@ -461,6 +462,7 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad, case GST_EVENT_EOS: basesink->preroll_queued++; basesink->eos = TRUE; + basesink->eos_queued = TRUE; break; case GST_EVENT_NEWSEGMENT: { @@ -475,6 +477,14 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad, basesink->have_newsegment = TRUE; + /* any other format with 0 also gives time 0, the other values are + * invalid as time though. */ + if (format != GST_FORMAT_TIME && segment_start == 0) { + format = GST_FORMAT_TIME; + segment_stop = -1; + basesink->segment_base = -1; + } + if (format != GST_FORMAT_TIME) { GST_DEBUG_OBJECT (basesink, "received non time %d NEW_SEGMENT %" G_GINT64_FORMAT @@ -633,7 +643,7 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad, GST_STATE_UNLOCK (basesink); /* reacquire stream lock, pad could be flushing now */ - /* FIXME in glib, if t==0, the lock is still taken... hmmm */ + /* FIXME in glib, if t==0, the lock is still taken... hmmm.. bug #317802 */ if (t > 0) GST_STREAM_LOCK_FULL (pad, t); @@ -812,18 +822,19 @@ gst_base_sink_event (GstPad * pad, GstEvent * event) if (bclass->event) bclass->event (basesink, event); + GST_LOCK (basesink); + basesink->flushing = TRUE; + if (basesink->clock_id) { + gst_clock_id_unschedule (basesink->clock_id); + } + GST_UNLOCK (basesink); + GST_PREROLL_LOCK (pad); /* we need preroll after the flush */ GST_DEBUG_OBJECT (basesink, "flushing, need preroll after flush"); basesink->need_preroll = TRUE; /* unlock from a possible state change/preroll */ gst_base_sink_preroll_queue_flush (basesink, pad); - - GST_LOCK (basesink); - if (basesink->clock_id) { - gst_clock_id_unschedule (basesink->clock_id); - } - GST_UNLOCK (basesink); GST_PREROLL_UNLOCK (pad); /* and we need to commit our state again on the next @@ -843,6 +854,9 @@ gst_base_sink_event (GstPad * pad, GstEvent * event) /* now we are completely unblocked and the _chain method * will return */ GST_STREAM_LOCK (pad); + GST_LOCK (basesink); + basesink->flushing = FALSE; + GST_UNLOCK (basesink); /* we need new segment info after the flush. */ basesink->segment_start = -1; basesink->segment_stop = -1; @@ -891,19 +905,27 @@ static GstClockReturn gst_base_sink_wait (GstBaseSink * basesink, GstClockTime time) { GstClockReturn ret; + GstClockID id; + + /* no need to attempt a clock wait if we are flushing */ + if (basesink->flushing) { + return GST_CLOCK_UNSCHEDULED; + } /* clock_id should be NULL outside of this function */ g_assert (basesink->clock_id == NULL); g_assert (GST_CLOCK_TIME_IS_VALID (time)); - basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock, time); + id = gst_clock_new_single_shot_id (basesink->clock, time); + basesink->clock_id = id; /* release the object lock while waiting */ GST_UNLOCK (basesink); - ret = gst_clock_id_wait (basesink->clock_id, NULL); - GST_LOCK (basesink); - gst_clock_id_unref (basesink->clock_id); + ret = gst_clock_id_wait (id, NULL); + + GST_LOCK (basesink); + gst_clock_id_unref (id); basesink->clock_id = NULL; return ret; @@ -1056,6 +1078,7 @@ gst_base_sink_handle_event (GstBaseSink * basesink, GstEvent * event) GST_DEBUG_OBJECT (basesink, "Now posting EOS"); gst_element_post_message (GST_ELEMENT (basesink), gst_message_new_eos (GST_OBJECT (basesink))); + basesink->eos_queued = FALSE; } GST_PREROLL_UNLOCK (basesink->sinkpad); break; @@ -1413,7 +1436,6 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) ret = GST_STATE_CHANGE_ASYNC; break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - { GST_PREROLL_LOCK (basesink->sinkpad); /* if we have EOS, we should empty the queue now as there will * be no more data received in the chain function. @@ -1421,7 +1443,17 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) * we are pushing and syncing the buffers, better start a new * thread to do this. */ if (basesink->eos) { + gboolean do_eos = !basesink->eos_queued; + gst_base_sink_preroll_queue_empty (basesink, basesink->sinkpad); + + /* need to post EOS message here if it was not in the preroll queue we + * just emptied. */ + if (do_eos) { + GST_DEBUG_OBJECT (basesink, "Now posting EOS"); + gst_element_post_message (GST_ELEMENT (basesink), + gst_message_new_eos (GST_OBJECT (basesink))); + } } else if (!basesink->have_preroll) { /* don't need preroll, but do queue a commit_state */ GST_DEBUG_OBJECT (basesink, @@ -1440,7 +1472,6 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) } GST_PREROLL_UNLOCK (basesink->sinkpad); break; - } default: break; } diff --git a/gst/base/gstbasesink.h b/gst/base/gstbasesink.h index 642e02598b..5baa7ba94d 100644 --- a/gst/base/gstbasesink.h +++ b/gst/base/gstbasesink.h @@ -72,6 +72,7 @@ struct _GstBaseSink { gint buffers_queued; gint events_queued; gboolean eos; + gboolean eos_queued; gboolean need_preroll; gboolean have_preroll; gboolean playing_async; @@ -93,6 +94,7 @@ struct _GstBaseSink { GstClockID clock_id; GstClockTime end_time; gboolean sync; + gboolean flushing; /*< private >*/ gpointer _gst_reserved[GST_PADDING]; diff --git a/libs/gst/base/gstbasesink.c b/libs/gst/base/gstbasesink.c index d2fc8c5add..f70e66aaf8 100644 --- a/libs/gst/base/gstbasesink.c +++ b/libs/gst/base/gstbasesink.c @@ -432,6 +432,7 @@ gst_base_sink_preroll_queue_flush (GstBaseSink * basesink, GstPad * pad) } /* we can't have EOS anymore now */ basesink->eos = FALSE; + basesink->eos_queued = FALSE; basesink->preroll_queued = 0; basesink->buffers_queued = 0; basesink->events_queued = 0; @@ -461,6 +462,7 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad, case GST_EVENT_EOS: basesink->preroll_queued++; basesink->eos = TRUE; + basesink->eos_queued = TRUE; break; case GST_EVENT_NEWSEGMENT: { @@ -475,6 +477,14 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad, basesink->have_newsegment = TRUE; + /* any other format with 0 also gives time 0, the other values are + * invalid as time though. */ + if (format != GST_FORMAT_TIME && segment_start == 0) { + format = GST_FORMAT_TIME; + segment_stop = -1; + basesink->segment_base = -1; + } + if (format != GST_FORMAT_TIME) { GST_DEBUG_OBJECT (basesink, "received non time %d NEW_SEGMENT %" G_GINT64_FORMAT @@ -633,7 +643,7 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad, GST_STATE_UNLOCK (basesink); /* reacquire stream lock, pad could be flushing now */ - /* FIXME in glib, if t==0, the lock is still taken... hmmm */ + /* FIXME in glib, if t==0, the lock is still taken... hmmm.. bug #317802 */ if (t > 0) GST_STREAM_LOCK_FULL (pad, t); @@ -812,18 +822,19 @@ gst_base_sink_event (GstPad * pad, GstEvent * event) if (bclass->event) bclass->event (basesink, event); + GST_LOCK (basesink); + basesink->flushing = TRUE; + if (basesink->clock_id) { + gst_clock_id_unschedule (basesink->clock_id); + } + GST_UNLOCK (basesink); + GST_PREROLL_LOCK (pad); /* we need preroll after the flush */ GST_DEBUG_OBJECT (basesink, "flushing, need preroll after flush"); basesink->need_preroll = TRUE; /* unlock from a possible state change/preroll */ gst_base_sink_preroll_queue_flush (basesink, pad); - - GST_LOCK (basesink); - if (basesink->clock_id) { - gst_clock_id_unschedule (basesink->clock_id); - } - GST_UNLOCK (basesink); GST_PREROLL_UNLOCK (pad); /* and we need to commit our state again on the next @@ -843,6 +854,9 @@ gst_base_sink_event (GstPad * pad, GstEvent * event) /* now we are completely unblocked and the _chain method * will return */ GST_STREAM_LOCK (pad); + GST_LOCK (basesink); + basesink->flushing = FALSE; + GST_UNLOCK (basesink); /* we need new segment info after the flush. */ basesink->segment_start = -1; basesink->segment_stop = -1; @@ -891,19 +905,27 @@ static GstClockReturn gst_base_sink_wait (GstBaseSink * basesink, GstClockTime time) { GstClockReturn ret; + GstClockID id; + + /* no need to attempt a clock wait if we are flushing */ + if (basesink->flushing) { + return GST_CLOCK_UNSCHEDULED; + } /* clock_id should be NULL outside of this function */ g_assert (basesink->clock_id == NULL); g_assert (GST_CLOCK_TIME_IS_VALID (time)); - basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock, time); + id = gst_clock_new_single_shot_id (basesink->clock, time); + basesink->clock_id = id; /* release the object lock while waiting */ GST_UNLOCK (basesink); - ret = gst_clock_id_wait (basesink->clock_id, NULL); - GST_LOCK (basesink); - gst_clock_id_unref (basesink->clock_id); + ret = gst_clock_id_wait (id, NULL); + + GST_LOCK (basesink); + gst_clock_id_unref (id); basesink->clock_id = NULL; return ret; @@ -1056,6 +1078,7 @@ gst_base_sink_handle_event (GstBaseSink * basesink, GstEvent * event) GST_DEBUG_OBJECT (basesink, "Now posting EOS"); gst_element_post_message (GST_ELEMENT (basesink), gst_message_new_eos (GST_OBJECT (basesink))); + basesink->eos_queued = FALSE; } GST_PREROLL_UNLOCK (basesink->sinkpad); break; @@ -1413,7 +1436,6 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) ret = GST_STATE_CHANGE_ASYNC; break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - { GST_PREROLL_LOCK (basesink->sinkpad); /* if we have EOS, we should empty the queue now as there will * be no more data received in the chain function. @@ -1421,7 +1443,17 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) * we are pushing and syncing the buffers, better start a new * thread to do this. */ if (basesink->eos) { + gboolean do_eos = !basesink->eos_queued; + gst_base_sink_preroll_queue_empty (basesink, basesink->sinkpad); + + /* need to post EOS message here if it was not in the preroll queue we + * just emptied. */ + if (do_eos) { + GST_DEBUG_OBJECT (basesink, "Now posting EOS"); + gst_element_post_message (GST_ELEMENT (basesink), + gst_message_new_eos (GST_OBJECT (basesink))); + } } else if (!basesink->have_preroll) { /* don't need preroll, but do queue a commit_state */ GST_DEBUG_OBJECT (basesink, @@ -1440,7 +1472,6 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) } GST_PREROLL_UNLOCK (basesink->sinkpad); break; - } default: break; } diff --git a/libs/gst/base/gstbasesink.h b/libs/gst/base/gstbasesink.h index 642e02598b..5baa7ba94d 100644 --- a/libs/gst/base/gstbasesink.h +++ b/libs/gst/base/gstbasesink.h @@ -72,6 +72,7 @@ struct _GstBaseSink { gint buffers_queued; gint events_queued; gboolean eos; + gboolean eos_queued; gboolean need_preroll; gboolean have_preroll; gboolean playing_async; @@ -93,6 +94,7 @@ struct _GstBaseSink { GstClockID clock_id; GstClockTime end_time; gboolean sync; + gboolean flushing; /*< private >*/ gpointer _gst_reserved[GST_PADDING];